diff options
Diffstat (limited to 'src')
667 files changed, 51356 insertions, 18845 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index aa63b5f516..2616eb8638 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,10 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +# Pattern rule to print variables, e.g. make print-top_srcdir +print-%: + @echo $* = $($*) + DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS) @@ -20,9 +24,8 @@ else LIBUNIVALUE = $(UNIVALUE_LIBS) endif -BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) +BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/secp256k1/include $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) -BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS) LIBBITCOIN_SERVER=libbitcoin_server.a @@ -93,15 +96,21 @@ endif if BUILD_BITCOIN_CLI bin_PROGRAMS += bitcoin-cli endif + if BUILD_BITCOIN_TX bin_PROGRAMS += bitcoin-tx endif + if ENABLE_WALLET if BUILD_BITCOIN_WALLET bin_PROGRAMS += bitcoin-wallet endif endif +if BUILD_BITCOIN_UTIL + bin_PROGRAMS += bitcoin-util +endif + .PHONY: FORCE check-symbols check-security # bitcoin core # BITCOIN_CORE_H = \ @@ -151,9 +160,9 @@ BITCOIN_CORE_H = \ interfaces/wallet.h \ key.h \ key_io.h \ - limitedmap.h \ logging.h \ logging/timer.h \ + mapport.h \ memusage.h \ merkleblock.h \ miner.h \ @@ -215,6 +224,7 @@ BITCOIN_CORE_H = \ timedata.h \ torcontrol.h \ txdb.h \ + txrequest.h \ txmempool.h \ undo.h \ util/asmap.h \ @@ -224,6 +234,7 @@ BITCOIN_CORE_H = \ util/error.h \ util/fees.h \ util/golombrice.h \ + util/hasher.h \ util/macros.h \ util/memory.h \ util/message.h \ @@ -236,6 +247,7 @@ BITCOIN_CORE_H = \ util/system.h \ util/threadnames.h \ util/time.h \ + util/trace.h \ util/translation.h \ util/ui_change_type.h \ util/url.h \ @@ -250,6 +262,7 @@ BITCOIN_CORE_H = \ wallet/context.h \ wallet/crypter.h \ wallet/db.h \ + wallet/dump.h \ wallet/feebumper.h \ wallet/fees.h \ wallet/ismine.h \ @@ -257,6 +270,7 @@ BITCOIN_CORE_H = \ wallet/rpcwallet.h \ wallet/salvage.h \ wallet/scriptpubkeyman.h \ + wallet/sqlite.h \ wallet/wallet.h \ wallet/walletdb.h \ wallet/wallettool.h \ @@ -298,14 +312,14 @@ libbitcoin_server_a_SOURCES = \ index/blockfilterindex.cpp \ index/txindex.cpp \ init.cpp \ - interfaces/chain.cpp \ - interfaces/node.cpp \ + mapport.cpp \ miner.cpp \ net.cpp \ net_processing.cpp \ node/coin.cpp \ node/coinstats.cpp \ node/context.cpp \ + node/interfaces.cpp \ node/psbt.cpp \ node/transaction.cpp \ node/ui_interface.cpp \ @@ -327,6 +341,7 @@ libbitcoin_server_a_SOURCES = \ timedata.cpp \ torcontrol.cpp \ txdb.cpp \ + txrequest.cpp \ txmempool.cpp \ validation.cpp \ validationinterface.cpp \ @@ -354,21 +369,20 @@ endif # wallet: shared between bitcoind and bitcoin-qt, but only linked # when wallet enabled -libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(SQLITE_CFLAGS) libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ - interfaces/wallet.cpp \ - wallet/bdb.cpp \ wallet/coincontrol.cpp \ wallet/context.cpp \ wallet/crypter.cpp \ wallet/db.cpp \ + wallet/dump.cpp \ wallet/feebumper.cpp \ wallet/fees.cpp \ + wallet/interfaces.cpp \ wallet/load.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ - wallet/salvage.cpp \ wallet/scriptpubkeyman.cpp \ wallet/wallet.cpp \ wallet/walletdb.cpp \ @@ -376,6 +390,13 @@ libbitcoin_wallet_a_SOURCES = \ wallet/coinselection.cpp \ $(BITCOIN_CORE_H) +if USE_SQLITE +libbitcoin_wallet_a_SOURCES += wallet/sqlite.cpp +endif +if USE_BDB +libbitcoin_wallet_a_SOURCES += wallet/bdb.cpp wallet/salvage.cpp +endif + libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_tool_a_SOURCES = \ @@ -401,6 +422,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \ crypto/hmac_sha512.h \ crypto/poly1305.h \ crypto/poly1305.cpp \ + crypto/muhash.h \ + crypto/muhash.cpp \ crypto/ripemd160.cpp \ crypto/ripemd160.h \ crypto/sha1.cpp \ @@ -533,6 +556,7 @@ libbitcoin_util_a_SOURCES = \ util/bytevectorhash.cpp \ util/error.cpp \ util/fees.cpp \ + util/hasher.cpp \ util/system.cpp \ util/message.cpp \ util/moneystr.cpp \ @@ -589,7 +613,7 @@ bitcoin_bin_ldadd = \ $(LIBMEMENV) \ $(LIBSECP256K1) -bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) +bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS) bitcoind_SOURCES = $(bitcoin_daemon_sources) bitcoind_CPPFLAGS = $(bitcoin_bin_cppflags) @@ -655,6 +679,27 @@ bitcoin_wallet_SOURCES += bitcoin-wallet-res.rc endif # +# bitcoin-util binary # +bitcoin_util_SOURCES = bitcoin-util.cpp +bitcoin_util_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +bitcoin_util_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +bitcoin_util_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) + +if TARGET_WINDOWS +bitcoin_util_SOURCES += bitcoin-util-res.rc +endif + +bitcoin_util_LDADD = \ + $(LIBBITCOIN_COMMON) \ + $(LIBBITCOIN_UTIL) \ + $(LIBUNIVALUE) \ + $(LIBBITCOIN_CONSENSUS) \ + $(LIBBITCOIN_CRYPTO) \ + $(LIBSECP256K1) + +bitcoin_util_LDADD += $(BOOST_LIBS) +# + # bitcoinconsensus library # if BUILD_BITCOIN_LIBS include_HEADERS = script/bitcoinconsensus.h @@ -735,13 +780,13 @@ endif if GLIBC_BACK_COMPAT @echo "Checking glibc back compat..." - $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS) + $(AM_V_at) CPPFILT=$(CPPFILT) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS) endif check-security: $(bin_PROGRAMS) if HARDEN @echo "Checking binary security..." - $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) OTOOL=$(OTOOL) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS) + $(AM_V_at) OBJDUMP=$(OBJDUMP) OTOOL=$(OTOOL) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS) endif if EMBEDDED_LEVELDB diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index bd9143a381..56b8ca8ce6 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -74,7 +74,7 @@ bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp endif -bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) +bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES) diff --git a/src/Makefile.crc32c.include b/src/Makefile.crc32c.include index 802b3a2e4b..113272e65e 100644 --- a/src/Makefile.crc32c.include +++ b/src/Makefile.crc32c.include @@ -41,7 +41,7 @@ crc32c_libcrc32c_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) crc32c_libcrc32c_a_SOURCES = crc32c_libcrc32c_a_SOURCES += crc32c/include/crc32c/crc32c.h crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_arm64.h -crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_arm64_linux_check.h +crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_arm64_check.h crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_internal.h crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_prefetch.h crc32c_libcrc32c_a_SOURCES += crc32c/src/crc32c_read_le.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 69ff0f0251..969f0ca411 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -78,6 +78,7 @@ QT_MOC_CPP = \ qt/moc_transactiondesc.cpp \ qt/moc_transactiondescdialog.cpp \ qt/moc_transactionfilterproxy.cpp \ + qt/moc_transactionoverviewwidget.cpp \ qt/moc_transactiontablemodel.cpp \ qt/moc_transactionview.cpp \ qt/moc_utilitydialog.cpp \ @@ -151,6 +152,7 @@ BITCOIN_QT_H = \ qt/transactiondesc.h \ qt/transactiondescdialog.h \ qt/transactionfilterproxy.h \ + qt/transactionoverviewwidget.h \ qt/transactionrecord.h \ qt/transactiontablemodel.h \ qt/transactionview.h \ @@ -320,8 +322,8 @@ if ENABLE_ZMQ bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ - $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ - $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) + $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \ + $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS) bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX @@ -379,11 +381,11 @@ ui_%.h: %.ui $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(UIC) -o $@ $< || (echo "Error creating $@"; false) %.moc: %.cpp - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES) $(MOC_DEFS) $< | \ + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES_UNSUPPRESSED) $(MOC_DEFS) $< | \ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ moc_%.cpp: %.h - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES) $(MOC_DEFS) $< | \ + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(MOC) $(DEFAULT_INCLUDES) $(QT_INCLUDES_UNSUPPRESSED) $(MOC_DEFS) $< | \ $(SED) -e '/^\*\*.*Created:/d' -e '/^\*\*.*by:/d' > $@ %.qm: %.ts diff --git a/src/Makefile.qt_locale.include b/src/Makefile.qt_locale.include index 3ac21b1326..aea42fd902 100644 --- a/src/Makefile.qt_locale.include +++ b/src/Makefile.qt_locale.include @@ -27,6 +27,7 @@ QT_TS = \ qt/locale/bitcoin_fi.ts \ qt/locale/bitcoin_fil.ts \ qt/locale/bitcoin_fr.ts \ + qt/locale/bitcoin_gl_ES.ts \ qt/locale/bitcoin_he.ts \ qt/locale/bitcoin_hi.ts \ qt/locale/bitcoin_hr.ts \ @@ -82,4 +83,5 @@ QT_TS = \ qt/locale/bitcoin_zh.ts \ qt/locale/bitcoin_zh_CN.ts \ qt/locale/bitcoin_zh_HK.ts \ - qt/locale/bitcoin_zh_TW.ts + qt/locale/bitcoin_zh_TW.ts \ + qt/locale/bitcoin_zu.ts diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index d300398b25..a6a857d952 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -55,8 +55,8 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \ - $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ - $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) + $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \ + $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS) qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 06dde87ddd..e9f9b73abe 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -2,167 +2,15 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -FUZZ_TARGETS = \ - test/fuzz/addition_overflow \ - test/fuzz/addr_info_deserialize \ - test/fuzz/addrdb \ - test/fuzz/address_deserialize \ - test/fuzz/addrman_deserialize \ - test/fuzz/asmap \ - test/fuzz/asmap_direct \ - test/fuzz/autofile \ - test/fuzz/banentry_deserialize \ - test/fuzz/banman \ - test/fuzz/base_encode_decode \ - test/fuzz/bech32 \ - test/fuzz/block \ - test/fuzz/block_deserialize \ - test/fuzz/block_file_info_deserialize \ - test/fuzz/block_filter_deserialize \ - test/fuzz/block_header \ - test/fuzz/block_header_and_short_txids_deserialize \ - test/fuzz/blockfilter \ - 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/bloom_filter \ - test/fuzz/bloomfilter_deserialize \ - test/fuzz/buffered_file \ - test/fuzz/chain \ - test/fuzz/checkqueue \ - test/fuzz/coins_deserialize \ - test/fuzz/coins_view \ - test/fuzz/crypto \ - test/fuzz/crypto_aes256 \ - test/fuzz/crypto_aes256cbc \ - test/fuzz/crypto_chacha20 \ - test/fuzz/crypto_chacha20_poly1305_aead \ - test/fuzz/crypto_common \ - test/fuzz/crypto_hkdf_hmac_sha256_l32 \ - test/fuzz/crypto_poly1305 \ - test/fuzz/cuckoocache \ - test/fuzz/decode_tx \ - test/fuzz/descriptor_parse \ - test/fuzz/diskblockindex_deserialize \ - test/fuzz/eval_script \ - test/fuzz/fee_rate \ - test/fuzz/fee_rate_deserialize \ - test/fuzz/fees \ - test/fuzz/flat_file_pos_deserialize \ - test/fuzz/flatfile \ - test/fuzz/float \ - test/fuzz/golomb_rice \ - test/fuzz/hex \ - test/fuzz/http_request \ - test/fuzz/integer \ - test/fuzz/inv_deserialize \ - test/fuzz/key \ - test/fuzz/key_io \ - test/fuzz/key_origin_info_deserialize \ - test/fuzz/kitchen_sink \ - test/fuzz/load_external_block_file \ - test/fuzz/locale \ - test/fuzz/merkle_block_deserialize \ - test/fuzz/merkleblock \ - test/fuzz/message \ - test/fuzz/messageheader_deserialize \ - test/fuzz/multiplication_overflow \ - test/fuzz/net \ - test/fuzz/net_permissions \ - test/fuzz/netaddr_deserialize \ - test/fuzz/netaddress \ - test/fuzz/out_point_deserialize \ - test/fuzz/p2p_transport_deserializer \ - test/fuzz/parse_hd_keypath \ - test/fuzz/parse_iso8601 \ - test/fuzz/parse_numbers \ - test/fuzz/parse_script \ - test/fuzz/parse_univalue \ - test/fuzz/partial_merkle_tree_deserialize \ - test/fuzz/partially_signed_transaction_deserialize \ - test/fuzz/policy_estimator \ - test/fuzz/policy_estimator_io \ - test/fuzz/pow \ - test/fuzz/prefilled_transaction_deserialize \ - test/fuzz/prevector \ - test/fuzz/primitives_transaction \ - test/fuzz/process_message \ - test/fuzz/process_message_addr \ - test/fuzz/process_message_block \ - test/fuzz/process_message_blocktxn \ - test/fuzz/process_message_cmpctblock \ - test/fuzz/process_message_feefilter \ - test/fuzz/process_message_filteradd \ - test/fuzz/process_message_filterclear \ - test/fuzz/process_message_filterload \ - test/fuzz/process_message_getaddr \ - test/fuzz/process_message_getblocks \ - test/fuzz/process_message_getblocktxn \ - test/fuzz/process_message_getdata \ - test/fuzz/process_message_getheaders \ - test/fuzz/process_message_headers \ - test/fuzz/process_message_inv \ - test/fuzz/process_message_mempool \ - test/fuzz/process_message_notfound \ - test/fuzz/process_message_ping \ - test/fuzz/process_message_pong \ - test/fuzz/process_message_sendcmpct \ - test/fuzz/process_message_sendheaders \ - test/fuzz/process_message_tx \ - test/fuzz/process_message_verack \ - test/fuzz/process_message_version \ - test/fuzz/process_messages \ - test/fuzz/protocol \ - test/fuzz/psbt \ - test/fuzz/psbt_input_deserialize \ - test/fuzz/psbt_output_deserialize \ - test/fuzz/pub_key_deserialize \ - test/fuzz/random \ - test/fuzz/rbf \ - test/fuzz/rolling_bloom_filter \ - test/fuzz/script \ - test/fuzz/script_bitcoin_consensus \ - test/fuzz/script_descriptor_cache \ - test/fuzz/script_deserialize \ - test/fuzz/script_flags \ - test/fuzz/script_interpreter \ - test/fuzz/script_ops \ - test/fuzz/script_sigcache \ - test/fuzz/script_sign \ - test/fuzz/scriptnum_ops \ - test/fuzz/secp256k1_ec_seckey_import_export_der \ - test/fuzz/secp256k1_ecdsa_signature_parse_der_lax \ - test/fuzz/service_deserialize \ - test/fuzz/signature_checker \ - test/fuzz/signet \ - test/fuzz/snapshotmetadata_deserialize \ - test/fuzz/span \ - test/fuzz/spanparsing \ - test/fuzz/string \ - test/fuzz/strprintf \ - test/fuzz/sub_net_deserialize \ - test/fuzz/system \ - test/fuzz/timedata \ - test/fuzz/transaction \ - test/fuzz/tx_in \ - test/fuzz/tx_in_deserialize \ - test/fuzz/tx_out \ - test/fuzz/txoutcompressor_deserialize \ - test/fuzz/txundo_deserialize \ - test/fuzz/uint160_deserialize \ - test/fuzz/uint256_deserialize - if ENABLE_FUZZ -noinst_PROGRAMS += $(FUZZ_TARGETS:=) +noinst_PROGRAMS += test/fuzz/fuzz else bin_PROGRAMS += test/test_bitcoin endif TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) +FUZZ_BINARY=test/fuzz/fuzz$(EXEEXT) JSON_TEST_FILES = \ test/data/script_tests.json \ @@ -235,7 +83,6 @@ BITCOIN_TESTS =\ test/interfaces_tests.cpp \ test/key_io_tests.cpp \ test/key_tests.cpp \ - test/limitedmap_tests.cpp \ test/logging_tests.cpp \ test/dbwrapper_tests.cpp \ test/validation_tests.cpp \ @@ -275,6 +122,7 @@ BITCOIN_TESTS =\ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ test/txindex_tests.cpp \ + test/txrequest_tests.cpp \ test/txvalidation_tests.cpp \ test/txvalidationcache_tests.cpp \ test/uint256_tests.cpp \ @@ -288,15 +136,19 @@ BITCOIN_TESTS =\ if ENABLE_WALLET BITCOIN_TESTS += \ - wallet/test/db_tests.cpp \ wallet/test/psbt_wallet_tests.cpp \ wallet/test/wallet_tests.cpp \ + wallet/test/walletdb_tests.cpp \ wallet/test/wallet_crypto_tests.cpp \ wallet/test/coinselector_tests.cpp \ wallet/test/init_tests.cpp \ wallet/test/ismine_tests.cpp \ wallet/test/scriptpubkeyman_tests.cpp +if USE_BDB +BITCOIN_TESTS += wallet/test/db_tests.cpp +endif + BITCOIN_TEST_SUITE += \ wallet/test/wallet_test_fixture.cpp \ wallet/test/wallet_test_fixture.h \ @@ -315,7 +167,7 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) +test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -static if ENABLE_ZMQ @@ -326,911 +178,106 @@ if ENABLE_FUZZ FUZZ_SUITE_LDFLAGS_COMMON = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -test_fuzz_addition_overflow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_addition_overflow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_addition_overflow_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_addition_overflow_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_addition_overflow_SOURCES = test/fuzz/addition_overflow.cpp - -test_fuzz_addr_info_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDR_INFO_DESERIALIZE=1 -test_fuzz_addr_info_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_addr_info_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_addr_info_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_addr_info_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_addrdb_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_addrdb_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_addrdb_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_addrdb_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_addrdb_SOURCES = test/fuzz/addrdb.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_address_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_address_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_addrman_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRMAN_DESERIALIZE=1 -test_fuzz_addrman_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_addrman_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_addrman_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_addrman_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_asmap_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_asmap_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_asmap_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_asmap_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_asmap_SOURCES = test/fuzz/asmap.cpp - -test_fuzz_asmap_direct_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_asmap_direct_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_asmap_direct_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_asmap_direct_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_asmap_direct_SOURCES = test/fuzz/asmap_direct.cpp - -test_fuzz_autofile_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_autofile_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_autofile_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_autofile_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_autofile_SOURCES = test/fuzz/autofile.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_banentry_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_banentry_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_banman_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_banman_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_banman_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_banman_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_banman_SOURCES = test/fuzz/banman.cpp - -test_fuzz_base_encode_decode_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_base_encode_decode_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_base_encode_decode_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_base_encode_decode_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_base_encode_decode_SOURCES = test/fuzz/base_encode_decode.cpp - -test_fuzz_bech32_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_bech32_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_bech32_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_bech32_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_bech32_SOURCES = test/fuzz/bech32.cpp - -test_fuzz_block_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_block_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_block_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_block_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_block_SOURCES = test/fuzz/block.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_block_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_block_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_block_file_info_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_FILE_INFO_DESERIALIZE=1 -test_fuzz_block_file_info_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_block_file_info_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_block_file_info_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_block_file_info_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_block_filter_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_FILTER_DESERIALIZE=1 -test_fuzz_block_filter_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_block_filter_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_block_filter_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_block_filter_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_block_header_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_block_header_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_block_header_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_block_header_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_block_header_SOURCES = test/fuzz/block_header.cpp - -test_fuzz_block_header_and_short_txids_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE=1 -test_fuzz_block_header_and_short_txids_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_block_header_and_short_txids_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_block_header_and_short_txids_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_block_header_and_short_txids_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_blockfilter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_blockfilter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_blockfilter_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_blockfilter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_blockfilter_SOURCES = test/fuzz/blockfilter.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_blockheader_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_blockheader_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_blocklocator_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKLOCATOR_DESERIALIZE=1 -test_fuzz_blocklocator_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_blocklocator_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_blocklocator_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_blocklocator_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_blockmerkleroot_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKMERKLEROOT=1 -test_fuzz_blockmerkleroot_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_blockmerkleroot_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_blockmerkleroot_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_blockmerkleroot_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_blocktransactions_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONS_DESERIALIZE=1 -test_fuzz_blocktransactions_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_blocktransactions_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_blocktransactions_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_blocktransactions_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_blocktransactionsrequest_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONSREQUEST_DESERIALIZE=1 -test_fuzz_blocktransactionsrequest_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_blocktransactionsrequest_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_blocktransactionsrequest_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_blocktransactionsrequest_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_blockundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKUNDO_DESERIALIZE=1 -test_fuzz_blockundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_blockundo_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_blockundo_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_blockundo_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_bloom_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_bloom_filter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_bloom_filter_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_bloom_filter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_bloom_filter_SOURCES = test/fuzz/bloom_filter.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_bloomfilter_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_bloomfilter_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_buffered_file_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_buffered_file_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_buffered_file_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_buffered_file_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_buffered_file_SOURCES = test/fuzz/buffered_file.cpp - -test_fuzz_chain_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_chain_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_chain_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_chain_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_chain_SOURCES = test/fuzz/chain.cpp - -test_fuzz_checkqueue_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_checkqueue_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_checkqueue_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_checkqueue_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_checkqueue_SOURCES = test/fuzz/checkqueue.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_coins_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_coins_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_coins_view_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_coins_view_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_coins_view_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_coins_view_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_coins_view_SOURCES = test/fuzz/coins_view.cpp - -test_fuzz_crypto_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_SOURCES = test/fuzz/crypto.cpp - -test_fuzz_crypto_aes256_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_aes256_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_aes256_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_aes256_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_aes256_SOURCES = test/fuzz/crypto_aes256.cpp - -test_fuzz_crypto_aes256cbc_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_aes256cbc_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_aes256cbc_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_aes256cbc_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_aes256cbc_SOURCES = test/fuzz/crypto_aes256cbc.cpp - -test_fuzz_crypto_chacha20_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_chacha20_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_chacha20_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_chacha20_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_chacha20_SOURCES = test/fuzz/crypto_chacha20.cpp - -test_fuzz_crypto_chacha20_poly1305_aead_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_chacha20_poly1305_aead_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_chacha20_poly1305_aead_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_chacha20_poly1305_aead_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_chacha20_poly1305_aead_SOURCES = test/fuzz/crypto_chacha20_poly1305_aead.cpp - -test_fuzz_crypto_common_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_common_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_common_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_common_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_common_SOURCES = test/fuzz/crypto_common.cpp - -test_fuzz_crypto_hkdf_hmac_sha256_l32_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_hkdf_hmac_sha256_l32_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_hkdf_hmac_sha256_l32_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_hkdf_hmac_sha256_l32_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_hkdf_hmac_sha256_l32_SOURCES = test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp - -test_fuzz_crypto_poly1305_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_crypto_poly1305_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_crypto_poly1305_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_crypto_poly1305_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_crypto_poly1305_SOURCES = test/fuzz/crypto_poly1305.cpp - -test_fuzz_cuckoocache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_cuckoocache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_cuckoocache_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_cuckoocache_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_cuckoocache_SOURCES = test/fuzz/cuckoocache.cpp - -test_fuzz_decode_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_decode_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_decode_tx_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_decode_tx_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_decode_tx_SOURCES = test/fuzz/decode_tx.cpp - -test_fuzz_descriptor_parse_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_descriptor_parse_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_descriptor_parse_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_descriptor_parse_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_descriptor_parse_SOURCES = test/fuzz/descriptor_parse.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_diskblockindex_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_diskblockindex_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_eval_script_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_eval_script_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_eval_script_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_eval_script_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_eval_script_SOURCES = test/fuzz/eval_script.cpp - -test_fuzz_fee_rate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_fee_rate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_fee_rate_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_fee_rate_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_fee_rate_SOURCES = test/fuzz/fee_rate.cpp - -test_fuzz_fee_rate_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DFEE_RATE_DESERIALIZE=1 -test_fuzz_fee_rate_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_fee_rate_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_fee_rate_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_fee_rate_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_fees_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_fees_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_fees_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_fees_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_fees_SOURCES = test/fuzz/fees.cpp - -test_fuzz_flat_file_pos_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DFLAT_FILE_POS_DESERIALIZE=1 -test_fuzz_flat_file_pos_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_flat_file_pos_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_flat_file_pos_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_flat_file_pos_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_flatfile_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_flatfile_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_flatfile_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_flatfile_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_flatfile_SOURCES = test/fuzz/flatfile.cpp - -test_fuzz_float_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_float_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_float_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_float_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_float_SOURCES = test/fuzz/float.cpp - -test_fuzz_golomb_rice_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_golomb_rice_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_golomb_rice_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_golomb_rice_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_golomb_rice_SOURCES = test/fuzz/golomb_rice.cpp - -test_fuzz_hex_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_hex_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_hex_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_hex_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_hex_SOURCES = test/fuzz/hex.cpp - -test_fuzz_http_request_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_http_request_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_http_request_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_http_request_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_http_request_SOURCES = test/fuzz/http_request.cpp - -test_fuzz_integer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_integer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_integer_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_integer_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_integer_SOURCES = test/fuzz/integer.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_inv_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_inv_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_key_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_key_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_key_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_key_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_key_SOURCES = test/fuzz/key.cpp - -test_fuzz_key_io_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_key_io_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_key_io_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_key_io_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_key_io_SOURCES = test/fuzz/key_io.cpp - -test_fuzz_key_origin_info_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DKEY_ORIGIN_INFO_DESERIALIZE=1 -test_fuzz_key_origin_info_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_key_origin_info_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_key_origin_info_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_key_origin_info_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_kitchen_sink_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_kitchen_sink_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_kitchen_sink_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_kitchen_sink_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_kitchen_sink_SOURCES = test/fuzz/kitchen_sink.cpp - -test_fuzz_load_external_block_file_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_load_external_block_file_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_load_external_block_file_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_load_external_block_file_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_load_external_block_file_SOURCES = test/fuzz/load_external_block_file.cpp - -test_fuzz_locale_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_locale_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_locale_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_locale_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_locale_SOURCES = test/fuzz/locale.cpp - -test_fuzz_merkle_block_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMERKLE_BLOCK_DESERIALIZE=1 -test_fuzz_merkle_block_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_merkle_block_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_merkle_block_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_merkle_block_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_merkleblock_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_merkleblock_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_merkleblock_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_merkleblock_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_merkleblock_SOURCES = test/fuzz/merkleblock.cpp - -test_fuzz_message_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_message_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_message_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_message_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_message_SOURCES = test/fuzz/message.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_messageheader_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_messageheader_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_multiplication_overflow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_multiplication_overflow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_multiplication_overflow_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_multiplication_overflow_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_multiplication_overflow_SOURCES = test/fuzz/multiplication_overflow.cpp - -test_fuzz_net_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_net_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_net_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_net_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_net_SOURCES = test/fuzz/net.cpp - -test_fuzz_net_permissions_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_net_permissions_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_net_permissions_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_net_permissions_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_net_permissions_SOURCES = test/fuzz/net_permissions.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_netaddr_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_netaddr_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_netaddress_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_netaddress_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_netaddress_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_netaddress_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_netaddress_SOURCES = test/fuzz/netaddress.cpp - -test_fuzz_out_point_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DOUT_POINT_DESERIALIZE=1 -test_fuzz_out_point_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_out_point_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_out_point_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_out_point_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_p2p_transport_deserializer_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_p2p_transport_deserializer_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_p2p_transport_deserializer_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_p2p_transport_deserializer_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_p2p_transport_deserializer_SOURCES = test/fuzz/p2p_transport_deserializer.cpp - -test_fuzz_parse_hd_keypath_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_parse_hd_keypath_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_parse_hd_keypath_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_parse_hd_keypath_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_parse_hd_keypath_SOURCES = test/fuzz/parse_hd_keypath.cpp - -test_fuzz_parse_iso8601_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_parse_iso8601_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_parse_iso8601_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_parse_iso8601_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_parse_iso8601_SOURCES = test/fuzz/parse_iso8601.cpp - -test_fuzz_parse_numbers_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_parse_numbers_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_parse_numbers_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_parse_numbers_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_parse_numbers_SOURCES = test/fuzz/parse_numbers.cpp - -test_fuzz_parse_script_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_parse_script_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_parse_script_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_parse_script_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_parse_script_SOURCES = test/fuzz/parse_script.cpp - -test_fuzz_parse_univalue_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_parse_univalue_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_parse_univalue_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_parse_univalue_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_parse_univalue_SOURCES = test/fuzz/parse_univalue.cpp - -test_fuzz_prevector_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_prevector_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_prevector_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_prevector_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_prevector_SOURCES = test/fuzz/prevector.cpp - -test_fuzz_partial_merkle_tree_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPARTIAL_MERKLE_TREE_DESERIALIZE=1 -test_fuzz_partial_merkle_tree_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_partial_merkle_tree_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_partial_merkle_tree_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_partial_merkle_tree_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_partially_signed_transaction_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPARTIALLY_SIGNED_TRANSACTION_DESERIALIZE=1 -test_fuzz_partially_signed_transaction_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_partially_signed_transaction_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_partially_signed_transaction_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_partially_signed_transaction_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_policy_estimator_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_policy_estimator_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_policy_estimator_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_policy_estimator_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_policy_estimator_SOURCES = test/fuzz/policy_estimator.cpp - -test_fuzz_policy_estimator_io_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_policy_estimator_io_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_policy_estimator_io_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_policy_estimator_io_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_policy_estimator_io_SOURCES = test/fuzz/policy_estimator_io.cpp - -test_fuzz_pow_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_pow_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_pow_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_pow_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_pow_SOURCES = test/fuzz/pow.cpp - -test_fuzz_prefilled_transaction_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPREFILLED_TRANSACTION_DESERIALIZE=1 -test_fuzz_prefilled_transaction_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_prefilled_transaction_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_prefilled_transaction_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_prefilled_transaction_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_primitives_transaction_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_primitives_transaction_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_primitives_transaction_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_primitives_transaction_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_primitives_transaction_SOURCES = test/fuzz/primitives_transaction.cpp - -test_fuzz_process_messages_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_process_messages_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_messages_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_messages_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_messages_SOURCES = test/fuzz/process_messages.cpp - -test_fuzz_process_message_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_process_message_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_addr_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=addr -test_fuzz_process_message_addr_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_addr_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_addr_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_addr_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_block_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=block -test_fuzz_process_message_block_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_block_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_block_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_block_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_blocktxn_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=blocktxn -test_fuzz_process_message_blocktxn_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_blocktxn_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_blocktxn_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_blocktxn_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_cmpctblock_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=cmpctblock -test_fuzz_process_message_cmpctblock_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_cmpctblock_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_cmpctblock_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_cmpctblock_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_feefilter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=feefilter -test_fuzz_process_message_feefilter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_feefilter_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_feefilter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_feefilter_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_filteradd_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=filteradd -test_fuzz_process_message_filteradd_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_filteradd_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_filteradd_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_filteradd_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_filterclear_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=filterclear -test_fuzz_process_message_filterclear_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_filterclear_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_filterclear_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_filterclear_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_filterload_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=filterload -test_fuzz_process_message_filterload_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_filterload_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_filterload_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_filterload_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_getaddr_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getaddr -test_fuzz_process_message_getaddr_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_getaddr_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_getaddr_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_getaddr_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_getblocks_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getblocks -test_fuzz_process_message_getblocks_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_getblocks_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_getblocks_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_getblocks_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_getblocktxn_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getblocktxn -test_fuzz_process_message_getblocktxn_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_getblocktxn_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_getblocktxn_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_getblocktxn_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_getdata_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getdata -test_fuzz_process_message_getdata_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_getdata_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_getdata_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_getdata_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_getheaders_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=getheaders -test_fuzz_process_message_getheaders_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_getheaders_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_getheaders_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_getheaders_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_headers_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=headers -test_fuzz_process_message_headers_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_headers_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_headers_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_headers_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_inv_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=inv -test_fuzz_process_message_inv_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_inv_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_inv_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_inv_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_mempool_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=mempool -test_fuzz_process_message_mempool_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_mempool_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_mempool_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_mempool_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_notfound_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=notfound -test_fuzz_process_message_notfound_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_notfound_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_notfound_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_notfound_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_ping_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=ping -test_fuzz_process_message_ping_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_ping_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_ping_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_ping_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_pong_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=pong -test_fuzz_process_message_pong_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_pong_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_pong_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_pong_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_sendcmpct_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=sendcmpct -test_fuzz_process_message_sendcmpct_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_sendcmpct_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_sendcmpct_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_sendcmpct_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_sendheaders_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=sendheaders -test_fuzz_process_message_sendheaders_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_sendheaders_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_sendheaders_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_sendheaders_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_tx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=tx -test_fuzz_process_message_tx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_tx_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_tx_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_tx_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_verack_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=verack -test_fuzz_process_message_verack_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_verack_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_verack_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_verack_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_process_message_version_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGE_TYPE=version -test_fuzz_process_message_version_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_process_message_version_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_process_message_version_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_process_message_version_SOURCES = test/fuzz/process_message.cpp - -test_fuzz_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_protocol_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_protocol_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_protocol_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_protocol_SOURCES = test/fuzz/protocol.cpp - -test_fuzz_psbt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_psbt_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_psbt_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_psbt_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_psbt_SOURCES = test/fuzz/psbt.cpp - -test_fuzz_psbt_input_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPSBT_INPUT_DESERIALIZE=1 -test_fuzz_psbt_input_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_psbt_input_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_psbt_input_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_psbt_input_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_psbt_output_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPSBT_OUTPUT_DESERIALIZE=1 -test_fuzz_psbt_output_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_psbt_output_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_psbt_output_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_psbt_output_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_pub_key_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DPUB_KEY_DESERIALIZE=1 -test_fuzz_pub_key_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_pub_key_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_pub_key_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_pub_key_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_random_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_random_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_random_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_random_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_random_SOURCES = test/fuzz/random.cpp - -test_fuzz_rbf_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_rbf_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_rbf_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_rbf_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_rbf_SOURCES = test/fuzz/rbf.cpp - -test_fuzz_rolling_bloom_filter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_rolling_bloom_filter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_rolling_bloom_filter_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_rolling_bloom_filter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_rolling_bloom_filter_SOURCES = test/fuzz/rolling_bloom_filter.cpp - -test_fuzz_script_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_SOURCES = test/fuzz/script.cpp - -test_fuzz_script_bitcoin_consensus_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_bitcoin_consensus_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_bitcoin_consensus_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_bitcoin_consensus_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_bitcoin_consensus_SOURCES = test/fuzz/script_bitcoin_consensus.cpp - -test_fuzz_script_descriptor_cache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_descriptor_cache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_descriptor_cache_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_descriptor_cache_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_descriptor_cache_SOURCES = test/fuzz/script_descriptor_cache.cpp - -test_fuzz_script_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSCRIPT_DESERIALIZE=1 -test_fuzz_script_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_script_flags_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_flags_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_flags_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_flags_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_flags_SOURCES = test/fuzz/script_flags.cpp - -test_fuzz_script_interpreter_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_interpreter_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_interpreter_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_interpreter_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_interpreter_SOURCES = test/fuzz/script_interpreter.cpp - -test_fuzz_script_ops_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_ops_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_ops_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_ops_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_ops_SOURCES = test/fuzz/script_ops.cpp - -test_fuzz_script_sigcache_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_sigcache_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_sigcache_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_sigcache_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_sigcache_SOURCES = test/fuzz/script_sigcache.cpp - -test_fuzz_script_sign_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_script_sign_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_script_sign_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_script_sign_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_script_sign_SOURCES = test/fuzz/script_sign.cpp - -test_fuzz_scriptnum_ops_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_scriptnum_ops_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_scriptnum_ops_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_scriptnum_ops_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_scriptnum_ops_SOURCES = test/fuzz/scriptnum_ops.cpp - -test_fuzz_secp256k1_ec_seckey_import_export_der_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_secp256k1_ec_seckey_import_export_der_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_secp256k1_ec_seckey_import_export_der_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_secp256k1_ec_seckey_import_export_der_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_secp256k1_ec_seckey_import_export_der_SOURCES = test/fuzz/secp256k1_ec_seckey_import_export_der.cpp - -test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_secp256k1_ecdsa_signature_parse_der_lax_SOURCES = test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_service_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_service_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_signature_checker_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_signature_checker_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_signature_checker_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_signature_checker_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_signature_checker_SOURCES = test/fuzz/signature_checker.cpp - -test_fuzz_signet_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_signet_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_signet_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_signet_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -test_fuzz_signet_SOURCES = test/fuzz/signet.cpp - -test_fuzz_snapshotmetadata_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSNAPSHOTMETADATA_DESERIALIZE=1 -test_fuzz_snapshotmetadata_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_snapshotmetadata_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_snapshotmetadata_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_snapshotmetadata_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_span_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_span_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_span_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_span_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_span_SOURCES = test/fuzz/span.cpp - -test_fuzz_spanparsing_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_spanparsing_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_spanparsing_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_spanparsing_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_spanparsing_SOURCES = test/fuzz/spanparsing.cpp - -test_fuzz_string_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_string_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_string_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_string_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_string_SOURCES = test/fuzz/string.cpp - -test_fuzz_strprintf_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_strprintf_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_strprintf_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_strprintf_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_strprintf_SOURCES = test/fuzz/strprintf.cpp - -test_fuzz_sub_net_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSUB_NET_DESERIALIZE=1 -test_fuzz_sub_net_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_sub_net_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_sub_net_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_sub_net_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_system_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_system_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_system_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_system_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_system_SOURCES = test/fuzz/system.cpp - -test_fuzz_timedata_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_timedata_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_timedata_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_timedata_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_timedata_SOURCES = test/fuzz/timedata.cpp - -test_fuzz_transaction_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_transaction_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_transaction_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_transaction_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_transaction_SOURCES = test/fuzz/transaction.cpp - -test_fuzz_tx_in_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_tx_in_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_tx_in_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_tx_in_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_tx_in_SOURCES = test/fuzz/tx_in.cpp - -test_fuzz_tx_in_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTX_IN_DESERIALIZE=1 -test_fuzz_tx_in_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_tx_in_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_tx_in_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_tx_in_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_tx_out_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -test_fuzz_tx_out_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_tx_out_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_tx_out_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_tx_out_SOURCES = test/fuzz/tx_out.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_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_txoutcompressor_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_txoutcompressor_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_txundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXUNDO_DESERIALIZE=1 -test_fuzz_txundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_txundo_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_txundo_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_txundo_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_uint160_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DUINT160_DESERIALIZE=1 -test_fuzz_uint160_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_uint160_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_uint160_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_uint160_deserialize_SOURCES = test/fuzz/deserialize.cpp - -test_fuzz_uint256_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DUINT256_DESERIALIZE=1 -test_fuzz_uint256_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -test_fuzz_uint256_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON) -test_fuzz_uint256_deserialize_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) -test_fuzz_uint256_deserialize_SOURCES = test/fuzz/deserialize.cpp +test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_fuzz_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_fuzz_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_fuzz_LDFLAGS = $(FUZZ_SUITE_LDFLAGS_COMMON) +test_fuzz_fuzz_SOURCES = \ + test/fuzz/addition_overflow.cpp \ + test/fuzz/addrdb.cpp \ + test/fuzz/addrman.cpp \ + test/fuzz/asmap.cpp \ + test/fuzz/asmap_direct.cpp \ + test/fuzz/autofile.cpp \ + test/fuzz/banman.cpp \ + test/fuzz/base_encode_decode.cpp \ + test/fuzz/bech32.cpp \ + test/fuzz/block.cpp \ + test/fuzz/block_header.cpp \ + test/fuzz/blockfilter.cpp \ + test/fuzz/bloom_filter.cpp \ + test/fuzz/buffered_file.cpp \ + test/fuzz/chain.cpp \ + test/fuzz/checkqueue.cpp \ + test/fuzz/coins_view.cpp \ + test/fuzz/connman.cpp \ + test/fuzz/crypto.cpp \ + test/fuzz/crypto_aes256.cpp \ + test/fuzz/crypto_aes256cbc.cpp \ + test/fuzz/crypto_chacha20.cpp \ + test/fuzz/crypto_chacha20_poly1305_aead.cpp \ + test/fuzz/crypto_common.cpp \ + test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \ + test/fuzz/crypto_poly1305.cpp \ + test/fuzz/cuckoocache.cpp \ + test/fuzz/data_stream.cpp \ + test/fuzz/decode_tx.cpp \ + test/fuzz/descriptor_parse.cpp \ + test/fuzz/deserialize.cpp \ + test/fuzz/eval_script.cpp \ + test/fuzz/fee_rate.cpp \ + test/fuzz/fees.cpp \ + test/fuzz/flatfile.cpp \ + test/fuzz/float.cpp \ + test/fuzz/golomb_rice.cpp \ + test/fuzz/hex.cpp \ + test/fuzz/http_request.cpp \ + test/fuzz/integer.cpp \ + test/fuzz/key.cpp \ + test/fuzz/key_io.cpp \ + test/fuzz/kitchen_sink.cpp \ + test/fuzz/load_external_block_file.cpp \ + test/fuzz/locale.cpp \ + test/fuzz/merkleblock.cpp \ + test/fuzz/message.cpp \ + test/fuzz/muhash.cpp \ + test/fuzz/multiplication_overflow.cpp \ + test/fuzz/net.cpp \ + test/fuzz/net_permissions.cpp \ + test/fuzz/netaddress.cpp \ + test/fuzz/node_eviction.cpp \ + test/fuzz/p2p_transport_deserializer.cpp \ + test/fuzz/parse_hd_keypath.cpp \ + test/fuzz/parse_iso8601.cpp \ + test/fuzz/parse_numbers.cpp \ + test/fuzz/parse_script.cpp \ + test/fuzz/parse_univalue.cpp \ + test/fuzz/policy_estimator.cpp \ + test/fuzz/policy_estimator_io.cpp \ + test/fuzz/pow.cpp \ + test/fuzz/prevector.cpp \ + test/fuzz/primitives_transaction.cpp \ + test/fuzz/process_message.cpp \ + test/fuzz/process_messages.cpp \ + test/fuzz/protocol.cpp \ + test/fuzz/psbt.cpp \ + test/fuzz/random.cpp \ + test/fuzz/rbf.cpp \ + test/fuzz/rolling_bloom_filter.cpp \ + test/fuzz/script.cpp \ + test/fuzz/script_assets_test_minimizer.cpp \ + test/fuzz/script_bitcoin_consensus.cpp \ + test/fuzz/script_descriptor_cache.cpp \ + test/fuzz/script_flags.cpp \ + test/fuzz/script_interpreter.cpp \ + test/fuzz/script_ops.cpp \ + test/fuzz/script_sigcache.cpp \ + test/fuzz/script_sign.cpp \ + test/fuzz/scriptnum_ops.cpp \ + test/fuzz/secp256k1_ec_seckey_import_export_der.cpp \ + test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp \ + test/fuzz/signature_checker.cpp \ + test/fuzz/signet.cpp \ + test/fuzz/span.cpp \ + test/fuzz/spanparsing.cpp \ + test/fuzz/string.cpp \ + test/fuzz/strprintf.cpp \ + test/fuzz/system.cpp \ + test/fuzz/timedata.cpp \ + test/fuzz/transaction.cpp \ + test/fuzz/tx_in.cpp \ + test/fuzz/tx_out.cpp \ + test/fuzz/txrequest.cpp endif # ENABLE_FUZZ @@ -1277,6 +324,11 @@ if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check endif +if ENABLE_FUZZ_LINK_ALL +all-local: $(FUZZ_BINARY) + bash ./test/fuzz/danger_link_all.sh +endif + %.cpp.test: %.cpp @echo Running tests: `cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1` from $< $(AM_V_at)$(TEST_BINARY) --catch_system_errors=no -l test_suite -t "`cat $< | grep -E "(BOOST_FIXTURE_TEST_SUITE\\(|BOOST_AUTO_TEST_SUITE\\()" | cut -d '(' -f 2 | cut -d ',' -f 1 | cut -d ')' -f 1`" -- DEBUG_LOG_OUT > $<.log 2>&1 || (cat $<.log && false) diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include index 4e858979fe..75fe68fcd1 100644 --- a/src/Makefile.test_fuzz.include +++ b/src/Makefile.test_fuzz.include @@ -16,6 +16,7 @@ libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAG libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libtest_fuzz_a_SOURCES = \ test/fuzz/fuzz.cpp \ + test/fuzz/util.cpp \ $(TEST_FUZZ_H) LIBTEST_FUZZ += $(LIBBITCOIN_SERVER) diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include index d7bc73defb..0621da8ddf 100644 --- a/src/Makefile.test_util.include +++ b/src/Makefile.test_util.include @@ -15,6 +15,7 @@ TEST_UTIL_H = \ test/util/setup_common.h \ test/util/str.h \ test/util/transaction_utils.h \ + test/util/validation.h \ test/util/wallet.h libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) @@ -27,6 +28,7 @@ libtest_util_a_SOURCES = \ test/util/setup_common.cpp \ test/util/str.cpp \ test/util/transaction_utils.cpp \ + test/util/validation.cpp \ test/util/wallet.cpp \ $(TEST_UTIL_H) diff --git a/src/addrdb.cpp b/src/addrdb.cpp index f3e8a19de2..8f77ed35ce 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,6 +10,7 @@ #include <clientversion.h> #include <cstdint> #include <hash.h> +#include <logging/timer.h> #include <random.h> #include <streams.h> #include <tinyformat.h> @@ -156,3 +157,22 @@ bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers) } return ret; } + +void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors) +{ + LOG_TIME_SECONDS(strprintf("Flush %d outbound block-relay-only peer addresses to anchors.dat", anchors.size())); + SerializeFileDB("anchors", anchors_db_path, anchors); +} + +std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path) +{ + std::vector<CAddress> anchors; + if (DeserializeFileDB(anchors_db_path, anchors)) { + LogPrintf("Loaded %i addresses from %s\n", anchors.size(), anchors_db_path.filename()); + } else { + anchors.clear(); + } + + fs::remove(anchors_db_path); + return anchors; +} diff --git a/src/addrdb.h b/src/addrdb.h index 8410c3776c..8953ebb169 100644 --- a/src/addrdb.h +++ b/src/addrdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,9 +11,9 @@ #include <serialize.h> #include <string> -#include <map> +#include <vector> -class CSubNet; +class CAddress; class CAddrMan; class CDataStream; @@ -73,4 +73,20 @@ public: bool Read(banmap_t& banSet); }; +/** + * Dump the anchor IP address database (anchors.dat) + * + * Anchors are last known outgoing block-relay-only peers that are + * tried to re-connect to on startup. + */ +void DumpAnchors(const fs::path& anchors_db_path, const std::vector<CAddress>& anchors); + +/** + * Read the anchor IP address database (anchors.dat) + * + * Deleting anchors.dat is intentional as it avoids renewed peering to anchors after + * an unclean shutdown and thus potential exploitation of the anchor peer policy. + */ +std::vector<CAddress> ReadAnchors(const fs::path& anchors_db_path); + #endif // BITCOIN_ADDRDB_H diff --git a/src/addrman.cpp b/src/addrman.cpp index 7636c6bad2..ed7fccc0ff 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -617,7 +617,7 @@ CAddrInfo CAddrMan::SelectTriedCollision_() return CAddrInfo(); } - CAddrInfo& newInfo = mapInfo[id_new]; + const CAddrInfo& newInfo = mapInfo[id_new]; // which tried bucket to move the entry to int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap); diff --git a/src/addrman.h b/src/addrman.h index ca045b91cd..9ac67b7af6 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -7,11 +7,13 @@ #define BITCOIN_ADDRMAN_H #include <clientversion.h> +#include <config/bitcoin-config.h> #include <netaddress.h> #include <protocol.h> #include <random.h> #include <sync.h> #include <timedata.h> +#include <tinyformat.h> #include <util/system.h> #include <fs.h> @@ -175,6 +177,28 @@ protected: mutable RecursiveMutex cs; private: + //! Serialization versions. + enum Format : uint8_t { + V0_HISTORICAL = 0, //!< historic format, before commit e6b343d88 + V1_DETERMINISTIC = 1, //!< for pre-asmap files + V2_ASMAP = 2, //!< for files including asmap version + V3_BIP155 = 3, //!< same as V2_ASMAP plus addresses are in BIP155 format + }; + + //! The maximum format this software knows it can unserialize. Also, we always serialize + //! in this format. + //! The format (first byte in the serialized stream) can be higher than this and + //! still this software may be able to unserialize the file - if the second byte + //! (see `lowest_compatible` in `Unserialize()`) is less or equal to this. + static constexpr Format FILE_FORMAT = Format::V3_BIP155; + + //! The initial value of a field that is incremented every time an incompatible format + //! change is made (such that old software versions would not be able to parse and + //! understand the new file format). This is 32 because we overtook the "key size" + //! field which was 32 historically. + //! @note Don't increment this. Increment `lowest_compatible` in `Serialize()` instead. + static constexpr uint8_t INCOMPATIBILITY_BASE = 32; + //! last used nId int nIdCount GUARDED_BY(cs); @@ -257,8 +281,18 @@ protected: //! Select several addresses at once. void GetAddr_(std::vector<CAddress> &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs); - //! Mark an entry as currently-connected-to. - void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs); + /** We have successfully connected to this peer. Calling this function + * updates the CAddress's nTime, which is used in our IsTerrible() + * decisions and gossiped to peers. Callers should be careful that updating + * this information doesn't leak topology information to network spies. + * + * net_processing calls this function when it *disconnects* from a peer to + * not leak information about currently connected peers. + * + * @param[in] addr The address of the peer we were connected to + * @param[in] nTime The time that we were last connected to this peer + */ + void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs); //! Update an entry's service bits. void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs); @@ -285,9 +319,19 @@ public: /** - * serialized format: - * * version byte (1 for pre-asmap files, 2 for files including asmap version) - * * 0x20 + nKey (serialized as if it were a vector, for backward compatibility) + * Serialized format. + * * format version byte (@see `Format`) + * * lowest compatible format version byte. This is used to help old software decide + * whether to parse the file. For example: + * * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is + * introduced in version N+1 that is compatible with format=3 and it is known that + * version N will be able to parse it, then version N+1 will write + * (format=4, lowest_compatible=3) in the first two bytes of the file, and so + * version N will still try to parse it. + * * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write + * (format=5, lowest_compatible=5) and so any versions that do not know how to parse + * format=5 will not try to read the file. + * * nKey * * nNew * * nTried * * number of "new" buckets XOR 2**30 @@ -313,14 +357,22 @@ public: * We don't use SERIALIZE_METHODS since the serialization and deserialization code has * very little in common. */ - template<typename Stream> - void Serialize(Stream &s) const + template <typename Stream> + void Serialize(Stream& s_) const { LOCK(cs); - unsigned char nVersion = 2; - s << nVersion; - s << ((unsigned char)32); + // Always serialize in the latest version (FILE_FORMAT). + + OverrideStream<Stream> s(&s_, s_.GetType(), s_.GetVersion() | ADDRV2_FORMAT); + + s << static_cast<uint8_t>(FILE_FORMAT); + + // Increment `lowest_compatible` iff a newly introduced format is incompatible with + // the previous one. + static constexpr uint8_t lowest_compatible = Format::V3_BIP155; + s << static_cast<uint8_t>(INCOMPATIBILITY_BASE + lowest_compatible); + s << nKey; s << nNew; s << nTried; @@ -370,23 +422,41 @@ public: s << asmap_version; } - template<typename Stream> - void Unserialize(Stream& s) + template <typename Stream> + void Unserialize(Stream& s_) { LOCK(cs); Clear(); - unsigned char nVersion; - s >> nVersion; - unsigned char nKeySize; - s >> nKeySize; - if (nKeySize != 32) throw std::ios_base::failure("Incorrect keysize in addrman deserialization"); + + Format format; + s_ >> Using<CustomUintFormatter<1>>(format); + + int stream_version = s_.GetVersion(); + if (format >= Format::V3_BIP155) { + // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress + // unserialize methods know that an address in addrv2 format is coming. + stream_version |= ADDRV2_FORMAT; + } + + OverrideStream<Stream> s(&s_, s_.GetType(), stream_version); + + uint8_t compat; + s >> compat; + const uint8_t lowest_compatible = compat - INCOMPATIBILITY_BASE; + if (lowest_compatible > FILE_FORMAT) { + throw std::ios_base::failure(strprintf( + "Unsupported format of addrman database: %u. It is compatible with formats >=%u, " + "but the maximum supported by this version of %s is %u.", + format, lowest_compatible, PACKAGE_NAME, static_cast<uint8_t>(FILE_FORMAT))); + } + s >> nKey; s >> nNew; s >> nTried; int nUBuckets = 0; s >> nUBuckets; - if (nVersion != 0) { + if (format >= Format::V1_DETERMINISTIC) { nUBuckets ^= (1 << 30); } @@ -449,7 +519,7 @@ public: supplied_asmap_version = SerializeHash(m_asmap); } uint256 serialized_asmap_version; - if (nVersion > 1) { + if (format >= Format::V2_ASMAP) { s >> serialized_asmap_version; } @@ -457,13 +527,13 @@ public: CAddrInfo &info = mapInfo[n]; int bucket = entryToBucket[n]; int nUBucketPos = info.GetBucketPosition(nKey, true, bucket); - if (nVersion == 2 && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && + if (format >= Format::V2_ASMAP && nUBuckets == ADDRMAN_NEW_BUCKET_COUNT && vvNew[bucket][nUBucketPos] == -1 && info.nRefCount < ADDRMAN_NEW_BUCKETS_PER_ADDRESS && serialized_asmap_version == supplied_asmap_version) { // Bucketing has not changed, using existing bucket positions for the new table vvNew[bucket][nUBucketPos] = n; info.nRefCount++; } else { - // In case the new table data cannot be used (nVersion unknown, bucket count wrong or new asmap), + // In case the new table data cannot be used (format unknown, bucket count wrong or new asmap), // try to give them a reference based on their primary source address. LogPrint(BCLog::ADDRMAN, "Bucketing method was updated, re-bucketing addrman entries from disk\n"); bucket = info.GetNewBucket(nKey, m_asmap); @@ -644,7 +714,7 @@ public: return vAddr; } - //! Mark an entry as currently-connected-to. + //! Outer function for Connected_() void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) { LOCK(cs); diff --git a/src/attributes.h b/src/attributes.h index 45099bd8b8..9957bcd84b 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -1,22 +1,19 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_ATTRIBUTES_H #define BITCOIN_ATTRIBUTES_H -#if defined(__has_cpp_attribute) -# if __has_cpp_attribute(nodiscard) -# define NODISCARD [[nodiscard]] -# endif -#endif -#ifndef NODISCARD -# if defined(_MSC_VER) && _MSC_VER >= 1700 -# define NODISCARD _Check_return_ +#if defined(__clang__) +# if __has_attribute(lifetimebound) +# define LIFETIMEBOUND [[clang::lifetimebound]] # else -# define NODISCARD __attribute__((warn_unused_result)) +# define LIFETIMEBOUND # endif +#else +# define LIFETIMEBOUND #endif #endif // BITCOIN_ATTRIBUTES_H diff --git a/src/banman.cpp b/src/banman.cpp index 8752185a60..49bf6c43dc 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -184,7 +184,7 @@ void BanMan::SweepBanned() while (it != m_banned.end()) { CSubNet sub_net = (*it).first; CBanEntry ban_entry = (*it).second; - if (now > ban_entry.nBanUntil) { + if (!sub_net.IsValid() || now > ban_entry.nBanUntil) { m_banned.erase(it++); m_is_dirty = true; notify_ui = true; diff --git a/src/base58.cpp b/src/base58.cpp index 0dc6044145..65e373283c 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -35,7 +35,7 @@ static const int8_t mapBase58[256] = { -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, }; -NODISCARD static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len) +[[nodiscard]] static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len) { // Skip leading spaces. while (*psz && IsSpace(*psz)) @@ -141,7 +141,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input) return EncodeBase58(vch); } -NODISCARD static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len) +[[nodiscard]] static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len) { if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) || (vchRet.size() < 4)) { diff --git a/src/base58.h b/src/base58.h index 468c3e2589..9ba5af73e0 100644 --- a/src/base58.h +++ b/src/base58.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -29,7 +29,7 @@ std::string EncodeBase58(Span<const unsigned char> input); * Decode a base58-encoded string (str) into a byte vector (vchRet). * return true if decoding is successful. */ -NODISCARD bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len); +[[nodiscard]] bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len); /** * Encode a byte span into a base58-encoded string, including checksum @@ -40,6 +40,6 @@ std::string EncodeBase58Check(Span<const unsigned char> input); * Decode a base58-encoded string (str) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -NODISCARD bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len); +[[nodiscard]] bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len); #endif // BITCOIN_BASE58_H diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp index 18cb5de196..6f6b4e3bfa 100644 --- a/src/bench/base58.cpp +++ b/src/bench/base58.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 3f15f3f856..af5a82f69f 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -49,7 +49,7 @@ static void AssembleBlock(benchmark::Bench& bench) for (const auto& txr : txs) { TxValidationState state; - bool ret{::AcceptToMemoryPool(*test_setup.m_node.mempool, state, txr, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)}; + bool ret{::AcceptToMemoryPool(*test_setup.m_node.mempool, state, txr, nullptr /* plTxnReplaced */, false /* bypass_limits */)}; assert(ret); } } diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index 116de98b14..d5275b0b76 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -45,7 +45,7 @@ static void CCoinsCaching(benchmark::Bench& bench) // Benchmark. const CTransaction tx_1(t1); bench.run([&] { - bool success = AreInputsStandard(tx_1, coins); + bool success = AreInputsStandard(tx_1, coins, false); assert(success); }); ECC_Stop(); diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp index 913e0f8d57..a6f4eec4ca 100644 --- a/src/bench/chacha20.cpp +++ b/src/bench/chacha20.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/chacha_poly_aead.cpp b/src/bench/chacha_poly_aead.cpp index 3b1d3e697a..e994279a4d 100644 --- a/src/bench/chacha_poly_aead.cpp +++ b/src/bench/chacha_poly_aead.cpp @@ -31,12 +31,15 @@ static void CHACHA20_POLY1305_AEAD(benchmark::Bench& bench, size_t buffersize, b uint32_t len = 0; bench.batch(buffersize).unit("byte").run([&] { // encrypt or decrypt the buffer with a static key - assert(aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true)); + const bool crypt_ok_1 = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true); + assert(crypt_ok_1); if (include_decryption) { // if we decrypt, include the GetLength - assert(aead.GetLength(&len, seqnr_aad, aad_pos, in.data())); - assert(aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true)); + const bool get_length_ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data()); + assert(get_length_ok); + const bool crypt_ok_2 = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true); + assert(crypt_ok_2); } // increase main sequence number diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index dc0aa4031c..a9f3f5f84d 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -34,7 +34,8 @@ static void DeserializeAndCheckBlockTest(benchmark::Bench& bench) char a = '\0'; stream.write(&a, 1); // Prevent compaction - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + ArgsManager bench_args; + const auto chainParams = CreateChainParams(bench_args, CBaseChainParams::MAIN); bench.unit("block").run([&] { CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp index ffa772d8c1..d7b8c1badc 100644 --- a/src/bench/checkqueue.cpp +++ b/src/bench/checkqueue.cpp @@ -10,8 +10,6 @@ #include <random.h> #include <util/system.h> -#include <boost/thread/thread.hpp> - #include <vector> static const size_t BATCHES = 101; @@ -44,12 +42,9 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) void swap(PrevectorJob& x){p.swap(x.p);}; }; CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE}; - boost::thread_group tg; // The main thread should be counted to prevent thread oversubscription, and // to decrease the variance of benchmark results. - for (auto x = 0; x < GetNumCores() - 1; ++x) { - tg.create_thread([&]{queue.Thread();}); - } + queue.StartWorkerThreads(GetNumCores() - 1); // create all the data once, then submit copies in the benchmark. FastRandomContext insecure_rand(true); @@ -70,8 +65,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) // it is done explicitly here for clarity control.Wait(); }); - tg.interrupt_all(); - tg.join_all(); + queue.StopWorkerThreads(); ECC_Stop(); } BENCHMARK(CCheckQueueSpeedPrevectorJob); diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 6af7e785de..3abfbfd784 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index 65d16d47d8..30fe11be6b 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -4,6 +4,7 @@ #include <bench/bench.h> +#include <crypto/muhash.h> #include <crypto/ripemd160.h> #include <crypto/sha1.h> #include <crypto/sha256.h> @@ -105,6 +106,54 @@ static void FastRandom_1bit(benchmark::Bench& bench) }); } +static void MuHash(benchmark::Bench& bench) +{ + MuHash3072 acc; + unsigned char key[32] = {0}; + int i = 0; + bench.run([&] { + key[0] = ++i; + acc *= MuHash3072(key); + }); +} + +static void MuHashMul(benchmark::Bench& bench) +{ + MuHash3072 acc; + FastRandomContext rng(true); + MuHash3072 muhash{rng.randbytes(32)}; + + bench.run([&] { + acc *= muhash; + }); +} + +static void MuHashDiv(benchmark::Bench& bench) +{ + MuHash3072 acc; + FastRandomContext rng(true); + MuHash3072 muhash{rng.randbytes(32)}; + + for (size_t i = 0; i < bench.epochIterations(); ++i) { + acc *= muhash; + } + + bench.run([&] { + acc /= muhash; + }); +} + +static void MuHashPrecompute(benchmark::Bench& bench) +{ + MuHash3072 acc; + FastRandomContext rng(true); + std::vector<unsigned char> key{rng.randbytes(32)}; + + bench.run([&] { + MuHash3072{key}; + }); +} + BENCHMARK(RIPEMD160); BENCHMARK(SHA1); BENCHMARK(SHA256); @@ -116,3 +165,8 @@ BENCHMARK(SipHash_32b); BENCHMARK(SHA256D64_1024); BENCHMARK(FastRandom_32bit); BENCHMARK(FastRandom_1bit); + +BENCHMARK(MuHash); +BENCHMARK(MuHashMul); +BENCHMARK(MuHashDiv); +BENCHMARK(MuHashPrecompute); diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp index ef83242e41..607e4392b7 100644 --- a/src/bench/gcs_filter.cpp +++ b/src/bench/gcs_filter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/hashpadding.cpp b/src/bench/hashpadding.cpp index 309cae3723..753c8c2881 100644 --- a/src/bench/hashpadding.cpp +++ b/src/bench/hashpadding.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2018 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp index 32b060a15a..b6d8824aba 100644 --- a/src/bench/lockedpool.cpp +++ b/src/bench/lockedpool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index 1b9e428c9d..db9a5661fd 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index 89233e390c..9b862b735c 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp index d8db99e7d4..cdef97c0ea 100644 --- a/src/bench/poly1305.cpp +++ b/src/bench/poly1305.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp index a2dbefa54a..dcd0e10285 100644 --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2018 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,24 +9,16 @@ #include <bench/bench.h> -// GCC 4.8 is missing some C++11 type_traits, -// https://www.gnu.org/software/gcc/gcc-5/changes.html -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 -#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor -#else -#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible -#endif - struct nontrivial_t { int x; nontrivial_t() :x(-1) {} SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); } }; -static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE<nontrivial_t>::value, +static_assert(!std::is_trivially_default_constructible<nontrivial_t>::value, "expected nontrivial_t to not be trivially constructible"); typedef unsigned char trivial_t; -static_assert(IS_TRIVIALLY_CONSTRUCTIBLE<trivial_t>::value, +static_assert(std::is_trivially_default_constructible<trivial_t>::value, "expected trivial_t to be trivially constructible"); template <typename T> diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp index 9b43951e6e..997ab56549 100644 --- a/src/bench/rollingbloom.cpp +++ b/src/bench/rollingbloom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 4b45264a3c..45ed9f60dc 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -7,12 +7,15 @@ #include <rpc/blockchain.h> #include <streams.h> +#include <test/util/setup_common.h> #include <validation.h> #include <univalue.h> static void BlockToJsonVerbose(benchmark::Bench& bench) { + TestingSetup test_setup{}; + CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION); char a = '\0'; stream.write(&a, 1); // Prevent compaction diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp index 1ff41765cf..f1eeef8885 100644 --- a/src/bench/rpc_mempool.cpp +++ b/src/bench/rpc_mempool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/util_time.cpp b/src/bench/util_time.cpp index fad179eb87..afc733482e 100644 --- a/src/bench/util_time.cpp +++ b/src/bench/util_time.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index 9af0b502eb..e3f6b35a7d 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -24,7 +24,7 @@ static void VerifyScriptBench(benchmark::Bench& bench) const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH; const int witnessversion = 0; - // Keypair. + // Key pair. CKey key; static const std::array<unsigned char, 32> vchKey = { { diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp index b3b73284d8..b385cec085 100644 --- a/src/bench/wallet_balance.cpp +++ b/src/bench/wallet_balance.cpp @@ -24,21 +24,19 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b const auto& ADDRESS_WATCHONLY = ADDRESS_BCRT1_UNSPENDABLE; - NodeContext node; - std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node); - CWallet wallet{chain.get(), "", CreateMockWalletDatabase()}; + CWallet wallet{test_setup.m_node.chain.get(), "", CreateMockWalletDatabase()}; { wallet.SetupLegacyScriptPubKeyMan(); bool first_run; if (wallet.LoadWallet(first_run) != DBErrors::LOAD_OK) assert(false); } - auto handler = chain->handleNotifications({&wallet, [](CWallet*) {}}); + auto handler = test_setup.m_node.chain->handleNotifications({&wallet, [](CWallet*) {}}); const Optional<std::string> address_mine{add_mine ? Optional<std::string>{getnewaddress(wallet)} : nullopt}; if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY); for (int i = 0; i < 100; ++i) { - generatetoaddress(test_setup.m_node, address_mine.get_value_or(ADDRESS_WATCHONLY)); + generatetoaddress(test_setup.m_node, address_mine.value_or(ADDRESS_WATCHONLY)); generatetoaddress(test_setup.m_node, ADDRESS_WATCHONLY); } SyncWithValidationInterfaceQueue(); diff --git a/src/bitcoin-cli-res.rc b/src/bitcoin-cli-res.rc index 58f8f1e8a2..405a302261 100644 --- a/src/bitcoin-cli-res.rc +++ b/src/bitcoin-cli-res.rc @@ -1,8 +1,8 @@ #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_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD) #define VER_FILEVERSION VER_PRODUCTVERSION #define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index aec4177b19..6a0d44a183 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -14,11 +14,13 @@ #include <rpc/mining.h> #include <rpc/protocol.h> #include <rpc/request.h> +#include <tinyformat.h> #include <util/strencodings.h> #include <util/system.h> #include <util/translation.h> #include <util/url.h> +#include <algorithm> #include <functional> #include <memory> #include <stdio.h> @@ -39,8 +41,6 @@ static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; static const bool DEFAULT_NAMED=false; static const int CONTINUE_EXECUTION=-1; -static const std::string ONION{".onion"}; -static const size_t ONION_LEN{ONION.size()}; /** Default number of blocks to generate for RPC generatetoaddress. */ static const std::string DEFAULT_NBLOCKS = "1"; @@ -57,9 +57,9 @@ static void SetupCliArgs(ArgsManager& argsman) argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC generatenewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0).", ArgsManager::ALLOW_INT, OptionsCategory::OPTIONS); + argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); SetupChainParamsBaseOptions(argsman); argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -298,66 +298,119 @@ public: class NetinfoRequestHandler : public BaseRequestHandler { private: - bool IsAddrIPv6(const std::string& addr) const + static constexpr int8_t UNKNOWN_NETWORK{-1}; + static constexpr uint8_t m_networks_size{3}; + const std::array<std::string, m_networks_size> m_networks{{"ipv4", "ipv6", "onion"}}; + std::array<std::array<uint16_t, m_networks_size + 2>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total/block-relay) + int8_t NetworkStringToId(const std::string& str) const { - return !addr.empty() && addr.front() == '['; - } - bool IsInboundOnion(const std::string& addr_local, int mapped_as) const - { - return mapped_as == 0 && addr_local.find(ONION) != std::string::npos; - } - bool IsOutboundOnion(const std::string& addr, int mapped_as) const - { - const size_t addr_len{addr.size()}; - const size_t onion_pos{addr.rfind(ONION)}; - return mapped_as == 0 && onion_pos != std::string::npos && addr_len > ONION_LEN && - (onion_pos == addr_len - ONION_LEN || onion_pos == addr.find_last_of(":") - ONION_LEN); + for (uint8_t i = 0; i < m_networks_size; ++i) { + if (str == m_networks.at(i)) return i; + } + return UNKNOWN_NETWORK; } - uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level + uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level + bool m_is_help_requested{false}; //!< Optional user-supplied arg to print help documentation bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; } bool IsAddressSelected() const { return m_details_level == 2 || m_details_level == 4; } bool IsVersionSelected() const { return m_details_level == 3 || m_details_level == 4; } - enum struct NetType { - ipv4, - ipv6, - onion, - }; + bool m_is_asmap_on{false}; + size_t m_max_addr_length{0}; + size_t m_max_age_length{4}; + size_t m_max_id_length{2}; struct Peer { - int id; - int mapped_as; - int version; - int64_t conn_time; + std::string addr; + std::string sub_version; + std::string network; + std::string age; + double min_ping; + double ping; int64_t last_blck; int64_t last_recv; int64_t last_send; int64_t last_trxn; - double min_ping; - double ping; - std::string addr; - std::string sub_version; - NetType net_type; + int id; + int mapped_as; + int version; bool is_block_relay; bool is_outbound; bool operator<(const Peer& rhs) const { return std::tie(is_outbound, min_ping) < std::tie(rhs.is_outbound, rhs.min_ping); } }; - std::string NetTypeEnumToString(NetType t) - { - switch (t) { - case NetType::ipv4: return "ipv4"; - case NetType::ipv6: return "ipv6"; - case NetType::onion: return "onion"; - } // no default case, so the compiler can warn about missing cases - assert(false); - } + std::vector<Peer> m_peers; std::string ChainToString() const { if (gArgs.GetChainName() == CBaseChainParams::TESTNET) return " testnet"; + if (gArgs.GetChainName() == CBaseChainParams::SIGNET) return " signet"; if (gArgs.GetChainName() == CBaseChainParams::REGTEST) return " regtest"; return ""; } + std::string PingTimeToString(double seconds) const + { + if (seconds < 0) return ""; + const double milliseconds{round(1000 * seconds)}; + return milliseconds > 999999 ? "-" : ToString(milliseconds); + } + const UniValue NetinfoHelp() + { + return std::string{ + "-netinfo level|\"help\" \n\n" + "Returns a network peer connections dashboard with information from the remote server.\n" + "Under the hood, -netinfo fetches the data by calling getpeerinfo and getnetworkinfo.\n" + "An optional integer argument from 0 to 4 can be passed for different peers listings.\n" + "Pass \"help\" to see this detailed help documentation.\n" + "If more than one argument is passed, only the first one is read and parsed.\n" + "Suggestion: use with the Linux watch(1) command for a live dashboard; see example below.\n\n" + "Arguments:\n" + "1. level (integer 0-4, optional) Specify the info level of the peers dashboard (default 0):\n" + " 0 - Connection counts and local addresses\n" + " 1 - Like 0 but with a peers listing (without address or version columns)\n" + " 2 - Like 1 but with an address column\n" + " 3 - Like 1 but with a version column\n" + " 4 - Like 1 but with both address and version columns\n" + "2. help (string \"help\", optional) Print this help documentation instead of the dashboard.\n\n" + "Result:\n\n" + "* The peers listing in levels 1-4 displays all of the peers sorted by direction and minimum ping time:\n\n" + " Column Description\n" + " ------ -----------\n" + " <-> Direction\n" + " \"in\" - inbound connections are those initiated by the peer\n" + " \"out\" - outbound connections are those initiated by us\n" + " type Type of peer connection\n" + " \"full\" - full relay, the default\n" + " \"block\" - block relay; like full relay but does not relay transactions or addresses\n" + " net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", or \"cjdns\")\n" + " mping Minimum observed ping time, in milliseconds (ms)\n" + " ping Last observed ping time, in milliseconds (ms)\n" + " send Time since last message sent to the peer, in seconds\n" + " recv Time since last message received from the peer, in seconds\n" + " txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n" + " blk Time since last novel block passing initial validity checks received from the peer, in minutes\n" + " age Duration of connection to the peer, in minutes\n" + " asmap Mapped AS (Autonomous System) number in the BGP route to the peer, used for diversifying\n" + " peer selection (only displayed if the -asmap config option is set)\n" + " id Peer index, in increasing order of peer connections since node startup\n" + " address IP address and port of the peer\n" + " version Peer version and subversion concatenated, e.g. \"70016/Satoshi:21.0.0/\"\n\n" + "* The connection counts table displays the number of peers by direction, network, and the totals\n" + " for each, as well as a column for block relay peers.\n\n" + "* The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n" + "Examples:\n\n" + "Connection counts and local addresses only\n" + "> bitcoin-cli -netinfo\n\n" + "Compact peers listing\n" + "> bitcoin-cli -netinfo 1\n\n" + "Full dashboard\n" + "> bitcoin-cli -netinfo 4\n\n" + "Full live dashboard, adjust --interval or --no-title as needed (Linux)\n" + "> watch --interval 1 --no-title bitcoin-cli -netinfo 4\n\n" + "See this help\n" + "> bitcoin-cli -netinfo help\n"}; + } + const int64_t m_time_now{GetSystemTimeInSeconds()}; + public: - const int ID_PEERINFO = 0; - const int ID_NETWORKINFO = 1; + static constexpr int ID_PEERINFO = 0; + static constexpr int ID_NETWORKINFO = 1; UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override { @@ -365,6 +418,10 @@ public: uint8_t n{0}; if (ParseUInt8(args.at(0), &n)) { m_details_level = n; + } else if (args.at(0) == "help") { + m_is_help_requested = true; + } else { + throw std::runtime_error(strprintf("invalid -netinfo argument: %s", args.at(0))); } } UniValue result(UniValue::VARR); @@ -375,6 +432,9 @@ public: UniValue ProcessReply(const UniValue& batch_in) override { + if (m_is_help_requested) { + return JSONRPCReplyObj(NetinfoHelp(), NullUniValue, 1); + } const std::vector<UniValue> batch{JSONRPCProcessBatchReply(batch_in)}; if (!batch[ID_PEERINFO]["error"].isNull()) return batch[ID_PEERINFO]; if (!batch[ID_NETWORKINFO]["error"].isNull()) return batch[ID_NETWORKINFO]; @@ -385,49 +445,25 @@ public: } // Count peer connection totals, and if DetailsRequested(), store peer data in a vector of structs. - const int64_t time_now{GetSystemTimeInSeconds()}; - int ipv4_i{0}, ipv6_i{0}, onion_i{0}, block_relay_i{0}, total_i{0}; // inbound conn counters - int ipv4_o{0}, ipv6_o{0}, onion_o{0}, block_relay_o{0}, total_o{0}; // outbound conn counters - size_t max_peer_id_length{2}, max_addr_length{0}; - bool is_asmap_on{false}; - std::vector<Peer> peers; - const UniValue& getpeerinfo{batch[ID_PEERINFO]["result"]}; - - for (const UniValue& peer : getpeerinfo.getValues()) { - const std::string addr{peer["addr"].get_str()}; - const std::string addr_local{peer["addrlocal"].isNull() ? "" : peer["addrlocal"].get_str()}; - const int mapped_as{peer["mapped_as"].isNull() ? 0 : peer["mapped_as"].get_int()}; + for (const UniValue& peer : batch[ID_PEERINFO]["result"].getValues()) { + const std::string network{peer["network"].get_str()}; + const int8_t network_id{NetworkStringToId(network)}; + if (network_id == UNKNOWN_NETWORK) continue; + const bool is_outbound{!peer["inbound"].get_bool()}; const bool is_block_relay{!peer["relaytxes"].get_bool()}; - const bool is_inbound{peer["inbound"].get_bool()}; - NetType net_type{NetType::ipv4}; - if (is_inbound) { - if (IsAddrIPv6(addr)) { - net_type = NetType::ipv6; - ++ipv6_i; - } else if (IsInboundOnion(addr_local, mapped_as)) { - net_type = NetType::onion; - ++onion_i; - } else { - ++ipv4_i; - } - if (is_block_relay) ++block_relay_i; - } else { - if (IsAddrIPv6(addr)) { - net_type = NetType::ipv6; - ++ipv6_o; - } else if (IsOutboundOnion(addr, mapped_as)) { - net_type = NetType::onion; - ++onion_o; - } else { - ++ipv4_o; - } - if (is_block_relay) ++block_relay_o; + ++m_counts.at(is_outbound).at(network_id); // in/out by network + ++m_counts.at(is_outbound).at(m_networks_size); // in/out overall + ++m_counts.at(2).at(network_id); // total by network + ++m_counts.at(2).at(m_networks_size); // total overall + if (is_block_relay) { + ++m_counts.at(is_outbound).at(m_networks_size + 1); // in/out block-relay + ++m_counts.at(2).at(m_networks_size + 1); // total block-relay } if (DetailsRequested()) { // Push data for this peer to the peers vector. const int peer_id{peer["id"].get_int()}; + const int mapped_as{peer["mapped_as"].isNull() ? 0 : peer["mapped_as"].get_int()}; const int version{peer["version"].get_int()}; - const std::string sub_version{peer["subver"].get_str()}; const int64_t conn_time{peer["conntime"].get_int64()}; const int64_t last_blck{peer["last_block"].get_int64()}; const int64_t last_recv{peer["lastrecv"].get_int64()}; @@ -435,10 +471,14 @@ public: const int64_t last_trxn{peer["last_transaction"].get_int64()}; const double min_ping{peer["minping"].isNull() ? -1 : peer["minping"].get_real()}; const double ping{peer["pingtime"].isNull() ? -1 : peer["pingtime"].get_real()}; - peers.push_back({peer_id, mapped_as, version, conn_time, last_blck, last_recv, last_send, last_trxn, min_ping, ping, addr, sub_version, net_type, is_block_relay, !is_inbound}); - max_peer_id_length = std::max(ToString(peer_id).length(), max_peer_id_length); - max_addr_length = std::max(addr.length() + 1, max_addr_length); - is_asmap_on |= (mapped_as != 0); + const std::string addr{peer["addr"].get_str()}; + const std::string age{conn_time == 0 ? "" : ToString((m_time_now - conn_time) / 60)}; + const std::string sub_version{peer["subver"].get_str()}; + m_peers.push_back({addr, sub_version, network, age, min_ping, ping, last_blck, last_recv, last_send, last_trxn, peer_id, mapped_as, version, is_block_relay, is_outbound}); + m_max_addr_length = std::max(addr.length() + 1, m_max_addr_length); + m_max_age_length = std::max(age.length(), m_max_age_length); + m_max_id_length = std::max(ToString(peer_id).length(), m_max_id_length); + m_is_asmap_on |= (mapped_as != 0); } } @@ -446,52 +486,56 @@ public: std::string result{strprintf("%s %s%s - %i%s\n\n", PACKAGE_NAME, FormatFullVersion(), ChainToString(), networkinfo["protocolversion"].get_int(), networkinfo["subversion"].get_str())}; // Report detailed peer connections list sorted by direction and minimum ping time. - if (DetailsRequested() && !peers.empty()) { - std::sort(peers.begin(), peers.end()); - result += "Peer connections sorted by direction and min ping\n<-> relay net mping ping send recv txn blk uptime "; - if (is_asmap_on) result += " asmap "; - result += strprintf("%*s %-*s%s\n", max_peer_id_length, "id", IsAddressSelected() ? max_addr_length : 0, IsAddressSelected() ? "address" : "", IsVersionSelected() ? "version" : ""); - for (const Peer& peer : peers) { + if (DetailsRequested() && !m_peers.empty()) { + std::sort(m_peers.begin(), m_peers.end()); + result += strprintf("<-> relay net mping ping send recv txn blk %*s ", m_max_age_length, "age"); + if (m_is_asmap_on) result += " asmap "; + result += strprintf("%*s %-*s%s\n", m_max_id_length, "id", IsAddressSelected() ? m_max_addr_length : 0, IsAddressSelected() ? "address" : "", IsVersionSelected() ? "version" : ""); + for (const Peer& peer : m_peers) { std::string version{ToString(peer.version) + peer.sub_version}; result += strprintf( - "%3s %5s %5s%6s%7s%5s%5s%5s%5s%7s%*i %*s %-*s%s\n", + "%3s %5s %5s%7s%7s%5s%5s%5s%5s %*s%*i %*s %-*s%s\n", peer.is_outbound ? "out" : "in", peer.is_block_relay ? "block" : "full", - NetTypeEnumToString(peer.net_type), - peer.min_ping == -1 ? "" : ToString(round(1000 * peer.min_ping)), - peer.ping == -1 ? "" : ToString(round(1000 * peer.ping)), - peer.last_send == 0 ? "" : ToString(time_now - peer.last_send), - peer.last_recv == 0 ? "" : ToString(time_now - peer.last_recv), - peer.last_trxn == 0 ? "" : ToString((time_now - peer.last_trxn) / 60), - peer.last_blck == 0 ? "" : ToString((time_now - peer.last_blck) / 60), - peer.conn_time == 0 ? "" : ToString((time_now - peer.conn_time) / 60), - is_asmap_on ? 7 : 0, // variable spacing - is_asmap_on && peer.mapped_as != 0 ? ToString(peer.mapped_as) : "", - max_peer_id_length, // variable spacing + peer.network, + PingTimeToString(peer.min_ping), + PingTimeToString(peer.ping), + peer.last_send == 0 ? "" : ToString(m_time_now - peer.last_send), + peer.last_recv == 0 ? "" : ToString(m_time_now - peer.last_recv), + peer.last_trxn == 0 ? "" : ToString((m_time_now - peer.last_trxn) / 60), + peer.last_blck == 0 ? "" : ToString((m_time_now - peer.last_blck) / 60), + m_max_age_length, // variable spacing + peer.age, + m_is_asmap_on ? 7 : 0, // variable spacing + m_is_asmap_on && peer.mapped_as != 0 ? ToString(peer.mapped_as) : "", + m_max_id_length, // variable spacing peer.id, - IsAddressSelected() ? max_addr_length : 0, // variable spacing + IsAddressSelected() ? m_max_addr_length : 0, // variable spacing IsAddressSelected() ? peer.addr : "", IsVersionSelected() && version != "0" ? version : ""); } - result += " ms ms sec sec min min min\n\n"; + result += strprintf(" ms ms sec sec min min %*s\n\n", m_max_age_length, "min"); } // Report peer connection totals by type. - total_i = ipv4_i + ipv6_i + onion_i; - total_o = ipv4_o + ipv6_o + onion_o; result += " ipv4 ipv6 onion total block-relay\n"; - result += strprintf("in %5i %5i %5i %5i %5i\n", ipv4_i, ipv6_i, onion_i, total_i, block_relay_i); - result += strprintf("out %5i %5i %5i %5i %5i\n", ipv4_o, ipv6_o, onion_o, total_o, block_relay_o); - result += strprintf("total %5i %5i %5i %5i %5i\n", ipv4_i + ipv4_o, ipv6_i + ipv6_o, onion_i + onion_o, total_i + total_o, block_relay_i + block_relay_o); + const std::array<std::string, 3> rows{{"in", "out", "total"}}; + for (uint8_t i = 0; i < m_networks_size; ++i) { + result += strprintf("%-5s %5i %5i %5i %5i %5i\n", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2), m_counts.at(i).at(m_networks_size), m_counts.at(i).at(m_networks_size + 1)); + } // Report local addresses, ports, and scores. result += "\nLocal addresses"; - const UniValue& local_addrs{networkinfo["localaddresses"]}; + const std::vector<UniValue>& local_addrs{networkinfo["localaddresses"].getValues()}; if (local_addrs.empty()) { result += ": n/a\n"; } else { - for (const UniValue& addr : local_addrs.getValues()) { - result += strprintf("\n%-40i port %5i score %6i", addr["address"].get_str(), addr["port"].get_int(), addr["score"].get_int()); + size_t max_addr_size{0}; + for (const UniValue& addr : local_addrs) { + max_addr_size = std::max(addr["address"].get_str().length() + 1, max_addr_size); + } + for (const UniValue& addr : local_addrs) { + result += strprintf("\n%-*s port %6i score %6i", max_addr_size, addr["address"].get_str(), addr["port"].get_int(), addr["score"].get_int()); } } @@ -596,6 +640,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co assert(output_headers); evhttp_add_header(output_headers, "Host", host.c_str()); evhttp_add_header(output_headers, "Connection", "close"); + evhttp_add_header(output_headers, "Content-Type", "application/json"); evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str()); // Attach request data diff --git a/src/bitcoin-tx-res.rc b/src/bitcoin-tx-res.rc index 3e49b820bc..b545ce9dbe 100644 --- a/src/bitcoin-tx-res.rc +++ b/src/bitcoin-tx-res.rc @@ -1,8 +1,8 @@ #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_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD) #define VER_FILEVERSION VER_PRODUCTVERSION #define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 085f1ecfda..321d62fe4d 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -11,6 +11,7 @@ #include <consensus/consensus.h> #include <core_io.h> #include <key_io.h> +#include <policy/policy.h> #include <policy/rbf.h> #include <primitives/transaction.h> #include <script/script.h> @@ -40,6 +41,7 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman) { SetupHelpOptions(argsman); + argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -95,13 +97,16 @@ static int AppInitRawTx(int argc, char* argv[]) fCreateBlank = gArgs.GetBoolArg("-create", false); - if (argc < 2 || HelpRequested(gArgs)) { + if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { // First part of help message is specific to this utility - std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n\n" + - "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n" + - "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n" + - "\n"; - strUsage += gArgs.GetHelpMessage(); + std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n"; + if (!gArgs.IsArgSet("-version")) { + strUsage += "\n" + "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n" + "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n" + "\n"; + strUsage += gArgs.GetHelpMessage(); + } tfm::format(std::cout, "%s", strUsage); @@ -192,8 +197,9 @@ static CAmount ExtractAndValidateValue(const std::string& strValue) static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) { int64_t newVersion; - if (!ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION) + if (!ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion > TX_MAX_STANDARD_VERSION) { throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'"); + } tx.nVersion = (int) newVersion; } @@ -594,7 +600,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) const int nOut = prevOut["vout"].get_int(); if (nOut < 0) - throw std::runtime_error("vout must be positive"); + throw std::runtime_error("vout cannot be negative"); COutPoint out(txid, nOut); std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey")); diff --git a/src/bitcoin-util-res.rc b/src/bitcoin-util-res.rc new file mode 100644 index 0000000000..3f0fa8ab6d --- /dev/null +++ b/src/bitcoin-util-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_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." 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-util (CLI Bitcoin utility)" + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", "bitcoin-util" + 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-util.exe" + VALUE "ProductName", "bitcoin-util" + 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-util.cpp b/src/bitcoin-util.cpp new file mode 100644 index 0000000000..af07b28d3d --- /dev/null +++ b/src/bitcoin-util.cpp @@ -0,0 +1,221 @@ +// Copyright (c) 2009-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <arith_uint256.h> +#include <clientversion.h> +#include <coins.h> +#include <consensus/consensus.h> +#include <core_io.h> +#include <key_io.h> +#include <policy/rbf.h> +#include <primitives/transaction.h> +#include <script/script.h> +#include <script/sign.h> +#include <script/signingprovider.h> +#include <univalue.h> +#include <util/moneystr.h> +#include <util/rbf.h> +#include <util/strencodings.h> +#include <util/string.h> +#include <util/system.h> +#include <util/translation.h> + +#include <atomic> +#include <functional> +#include <memory> +#include <stdio.h> +#include <thread> + +#include <boost/algorithm/string.hpp> + +static const int CONTINUE_EXECUTION=-1; + +const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; + +static void SetupBitcoinUtilArgs(ArgsManager &argsman) +{ + SetupHelpOptions(argsman); + + argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + + SetupChainParamsBaseOptions(argsman); +} + +// This function returns either one of EXIT_ codes when it's expected to stop the process or +// CONTINUE_EXECUTION when it's expected to continue further. +static int AppInitUtil(int argc, char* argv[]) +{ + SetupBitcoinUtilArgs(gArgs); + std::string error; + if (!gArgs.ParseParameters(argc, argv, error)) { + tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error); + return EXIT_FAILURE; + } + + // Check for chain settings (Params() calls are only valid after this clause) + try { + SelectParams(gArgs.GetChainName()); + } catch (const std::exception& e) { + tfm::format(std::cerr, "Error: %s\n", e.what()); + return EXIT_FAILURE; + } + + if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { + // First part of help message is specific to this utility + std::string strUsage = PACKAGE_NAME " bitcoin-util utility version " + FormatFullVersion() + "\n"; + if (!gArgs.IsArgSet("-version")) { + strUsage += "\n" + "Usage: bitcoin-util [options] [commands] Do stuff\n"; + strUsage += "\n" + gArgs.GetHelpMessage(); + } + + tfm::format(std::cout, "%s", strUsage); + + if (argc < 2) { + tfm::format(std::cerr, "Error: too few parameters\n"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; + } + return CONTINUE_EXECUTION; +} + +static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offset, uint32_t step, std::atomic<bool>& found) +{ + arith_uint256 target; + bool neg, over; + target.SetCompact(nBits, &neg, &over); + if (target == 0 || neg || over) return; + CBlockHeader header = header_orig; // working copy + header.nNonce = offset; + + uint32_t finish = std::numeric_limits<uint32_t>::max() - step; + finish = finish - (finish % step) + offset; + + while (!found && header.nNonce < finish) { + const uint32_t next = (finish - header.nNonce < 5000*step) ? finish : header.nNonce + 5000*step; + do { + if (UintToArith256(header.GetHash()) <= target) { + if (!found.exchange(true)) { + header_orig.nNonce = header.nNonce; + } + return; + } + header.nNonce += step; + } while(header.nNonce != next); + } +} + +static int Grind(int argc, char* argv[], std::string& strPrint) +{ + if (argc != 1) { + strPrint = "Must specify block header to grind"; + return 1; + } + + CBlockHeader header; + if (!DecodeHexBlockHeader(header, argv[0])) { + strPrint = "Could not decode block header"; + return 1; + } + + uint32_t nBits = header.nBits; + std::atomic<bool> found{false}; + + std::vector<std::thread> threads; + int n_tasks = std::max(1u, std::thread::hardware_concurrency()); + for (int i = 0; i < n_tasks; ++i) { + threads.emplace_back( grind_task, nBits, std::ref(header), i, n_tasks, std::ref(found) ); + } + for (auto& t : threads) { + t.join(); + } + if (!found) { + strPrint = "Could not satisfy difficulty target"; + return 1; + } + + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << header; + strPrint = HexStr(ss); + return 0; +} + +static int CommandLineUtil(int argc, char* argv[]) +{ + if (argc <= 1) return 1; + + std::string strPrint; + int nRet = 0; + + try { + while (argc > 1 && IsSwitchChar(argv[1][0]) && (argv[1][1] != 0)) { + --argc; + ++argv; + } + + char* command = argv[1]; + if (strcmp(command, "grind") == 0) { + nRet = Grind(argc-2, argv+2, strPrint); + } else { + strPrint = strprintf("Unknown command %s", command); + nRet = 1; + } + } + catch (const std::exception& e) { + strPrint = std::string("error: ") + e.what(); + nRet = EXIT_FAILURE; + } + catch (...) { + PrintExceptionContinue(nullptr, "CommandLineUtil()"); + throw; + } + + if (strPrint != "") { + tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint); + } + return nRet; +} + +#ifdef WIN32 +// Export main() and ensure working ASLR on Windows. +// Exporting a symbol will prevent the linker from stripping +// the .reloc section from the binary, which is a requirement +// for ASLR. This is a temporary workaround until a fixed +// version of binutils is used for releases. +__declspec(dllexport) int main(int argc, char* argv[]) +#else +int main(int argc, char* argv[]) +#endif +{ + SetupEnvironment(); + + try { + int ret = AppInitUtil(argc, argv); + if (ret != CONTINUE_EXECUTION) + return ret; + } + catch (const std::exception& e) { + PrintExceptionContinue(&e, "AppInitUtil()"); + return EXIT_FAILURE; + } catch (...) { + PrintExceptionContinue(nullptr, "AppInitUtil()"); + return EXIT_FAILURE; + } + + int ret = EXIT_FAILURE; + try { + ret = CommandLineUtil(argc, argv); + } + catch (const std::exception& e) { + PrintExceptionContinue(&e, "CommandLineUtil()"); + } catch (...) { + PrintExceptionContinue(nullptr, "CommandLineUtil()"); + } + return ret; +} diff --git a/src/bitcoin-wallet-res.rc b/src/bitcoin-wallet-res.rc index e9fa2dbb40..59346ab8f6 100644 --- a/src/bitcoin-wallet-res.rc +++ b/src/bitcoin-wallet-res.rc @@ -1,8 +1,8 @@ #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_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD) #define VER_FILEVERSION VER_PRODUCTVERSION #define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 8fdf1bae0f..3e8e5fc7bc 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -24,14 +24,20 @@ static void SetupWalletToolArgs(ArgsManager& argsman) SetupHelpOptions(argsman); SetupChainParamsBaseOptions(argsman); + argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-wallet=<wallet-name>", "Specify wallet name", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS); + argsman.AddArg("-dumpfile=<file name>", "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.", ArgsManager::ALLOW_STRING, OptionsCategory::OPTIONS); argsman.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS); + argsman.AddArg("-format=<format>", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("info", "Get wallet info", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); argsman.AddArg("create", "Create new wallet file", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); - argsman.AddArg("salvage", "Attempt to recover private keys from a corrupt wallet", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); + argsman.AddArg("salvage", "Attempt to recover private keys from a corrupt wallet. Warning: 'salvage' is experimental.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); + argsman.AddArg("dump", "Print out all of the wallet key-value records", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); + argsman.AddArg("createfromdump", "Create new wallet file from dumped records", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); } static bool WalletAppInit(int argc, char* argv[]) @@ -42,16 +48,18 @@ static bool WalletAppInit(int argc, char* argv[]) tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error_message); return false; } - if (argc < 2 || HelpRequested(gArgs)) { - std::string usage = strprintf("%s bitcoin-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n\n" + - "bitcoin-wallet is an offline tool for creating and interacting with " PACKAGE_NAME " wallet files.\n" + - "By default bitcoin-wallet will act on wallets in the default mainnet wallet directory in the datadir.\n" + - "To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n" + - "Usage:\n" + - " bitcoin-wallet [options] <command>\n\n" + - gArgs.GetHelpMessage(); - - tfm::format(std::cout, "%s", usage); + if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { + std::string strUsage = strprintf("%s bitcoin-wallet version", PACKAGE_NAME) + " " + FormatFullVersion() + "\n"; + if (!gArgs.IsArgSet("-version")) { + strUsage += "\n" + "bitcoin-wallet is an offline tool for creating and interacting with " PACKAGE_NAME " wallet files.\n" + "By default bitcoin-wallet will act on wallets in the default mainnet wallet directory in the datadir.\n" + "To change the target wallet, use the -datadir, -wallet and -testnet/-regtest arguments.\n\n" + "Usage:\n" + " bitcoin-wallet [options] <command>\n"; + strUsage += "\n" + gArgs.GetHelpMessage(); + } + tfm::format(std::cout, "%s", strUsage); return false; } @@ -112,8 +120,9 @@ int main(int argc, char* argv[]) ECCVerifyHandle globalVerifyHandle; ECC_Start(); - if (!WalletTool::ExecuteWalletToolFunc(method, name)) + if (!WalletTool::ExecuteWalletToolFunc(gArgs, method, name)) { return EXIT_FAILURE; + } ECC_Stop(); return EXIT_SUCCESS; } diff --git a/src/bitcoind-res.rc b/src/bitcoind-res.rc index 3a64acd5d1..a98b50c899 100644 --- a/src/bitcoind-res.rc +++ b/src/bitcoind-res.rc @@ -1,8 +1,8 @@ #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_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD) #define VER_FILEVERSION VER_PRODUCTVERSION #define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 455a82e390..b7bcb534ef 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -28,15 +28,6 @@ const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; UrlDecodeFn* const URL_DECODE = urlDecode; -static void WaitForShutdown(NodeContext& node) -{ - while (!ShutdownRequested()) - { - UninterruptibleSleep(std::chrono::milliseconds{200}); - } - Interrupt(node); -} - static bool AppInit(int argc, char* argv[]) { NodeContext node; @@ -57,11 +48,11 @@ static bool AppInit(int argc, char* argv[]) if (HelpRequested(args) || args.IsArgSet("-version")) { std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n"; - if (args.IsArgSet("-version")) { - strUsage += FormatParagraph(LicenseInfo()) + "\n"; - } else { - strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n"; - strUsage += "\n" + args.GetHelpMessage(); + if (!args.IsArgSet("-version")) { + strUsage += FormatParagraph(LicenseInfo()) + "\n" + "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n" + "\n"; + strUsage += args.GetHelpMessage(); } tfm::format(std::cout, "%s", strUsage); @@ -147,12 +138,10 @@ static bool AppInit(int argc, char* argv[]) PrintExceptionContinue(nullptr, "AppInit()"); } - if (!fRet) - { - Interrupt(node); - } else { - WaitForShutdown(node); + if (fRet) { + WaitForShutdown(); } + Interrupt(node); Shutdown(node); return fRet; diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index a47709cd82..aa111b5939 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index 9a6fb4abd0..41fa0b6fa0 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bloom.cpp b/src/bloom.cpp index d182f0728e..d0128a26d7 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/bloom.h b/src/bloom.h index 9307257852..fdaa8abfb2 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -94,7 +94,18 @@ public: * insert()'ed ... but may also return true for items that were not inserted. * * It needs around 1.8 bytes per element per factor 0.1 of false positive rate. - * (More accurately: 3/(log(256)*log(2)) * log(1/fpRate) * nElements bytes) + * For example, if we want 1000 elements, we'd need: + * - ~1800 bytes for a false positive rate of 0.1 + * - ~3600 bytes for a false positive rate of 0.01 + * - ~5400 bytes for a false positive rate of 0.001 + * + * If we make these simplifying assumptions: + * - logFpRate / log(0.5) doesn't get rounded or clamped in the nHashFuncs calculation + * - nElements is even, so that nEntriesPerGeneration == nElements / 2 + * + * Then we get a more accurate estimate for filter bytes: + * + * 3/(log(256)*log(2)) * log(1/fpRate) * nElements */ class CRollingBloomFilter { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index d7f7888ef3..88cf5ef0a8 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -86,11 +86,13 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000e1ab5ec9348e9f4b8eb8154"); + // Deployment of Taproot (BIPs 340-342) + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1230767999; // December 31, 2008 - // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x0000000000000000000f2adce67e49b0b6bdeb9de8b7c3d7e93b21e7fc1e819d"); // 623950 + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000001533efd8d716a517fe2c5008"); + consensus.defaultAssumeValid = uint256S("0x0000000000000000000b9d2ec5a352ecba0592946514a92f14319dc2b367fc72"); // 654683 /** * The message start string is designed to be unlikely to occur in normal data. @@ -103,8 +105,8 @@ public: pchMessageStart[3] = 0xd9; nDefaultPort = 8333; nPruneAfterHeight = 100000; - m_assumed_blockchain_size = 320; - m_assumed_chain_state_size = 4; + m_assumed_blockchain_size = 350; + m_assumed_chain_state_size = 6; genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); @@ -160,10 +162,10 @@ public: }; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 0000000000000000000f2adce67e49b0b6bdeb9de8b7c3d7e93b21e7fc1e819d - /* nTime */ 1585764811, - /* nTxCount */ 517186863, - /* dTxRate */ 3.305709665792344, + // Data from RPC: getchaintxstats 4096 0000000000000000000b9d2ec5a352ecba0592946514a92f14319dc2b367fc72 + /* nTime */ 1603995752, + /* nTxCount */ 582083445, + /* dTxRate */ 3.508976121410527, }; } }; @@ -197,11 +199,13 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 - // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000001495c1d5a01e2af8a23"); + // Deployment of Taproot (BIPs 340-342) + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1230767999; // December 31, 2008 - // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x000000000000056c49030c174179b52a928c870e6e8a822c75973b7970cfbd01"); // 1692000 + consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000001db6ec4ac88cf2272c6"); + consensus.defaultAssumeValid = uint256S("0x000000000000006433d1efec504c53ca332b64963c425395515b01977bd7b3b0"); // 1864000 pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -247,10 +251,10 @@ public: }; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 000000000000056c49030c174179b52a928c870e6e8a822c75973b7970cfbd01 - /* nTime */ 1585561140, - /* nTxCount */ 13483, - /* dTxRate */ 0.08523187013249722, + // Data from RPC: getchaintxstats 4096 000000000000006433d1efec504c53ca332b64963c425395515b01977bd7b3b0 + /* nTime */ 1603359686, + /* nTxCount */ 58090238, + /* dTxRate */ 0.1232886622799463, }; } }; @@ -265,11 +269,21 @@ public: vSeeds.clear(); if (!args.IsArgSet("-signetchallenge")) { - LogPrintf("Using default signet network\n"); bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae"); vSeeds.emplace_back("178.128.221.177"); vSeeds.emplace_back("2a01:7c8:d005:390::5"); - vSeeds.emplace_back("ntv3mtqw5wt63red.onion:38333"); + vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333"); + + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000000019fd16269a"); + consensus.defaultAssumeValid = uint256S("0x0000002a1de0f46379358c1fd09906f7ac59adf3712323ed90eb59e4c183c020"); // 9434 + m_assumed_blockchain_size = 1; + m_assumed_chain_state_size = 0; + chainTxData = ChainTxData{ + // Data from RPC: getchaintxstats 4096 0000002a1de0f46379358c1fd09906f7ac59adf3712323ed90eb59e4c183c020 + /* nTime */ 1603986000, + /* nTxCount */ 9582, + /* dTxRate */ 0.00159272030651341, + }; } else { const auto signet_challenge = args.GetArgs("-signetchallenge"); if (signet_challenge.size() != 1) { @@ -277,6 +291,15 @@ public: } bin = ParseHex(signet_challenge[0]); + consensus.nMinimumChainWork = uint256{}; + consensus.defaultAssumeValid = uint256{}; + m_assumed_blockchain_size = 0; + m_assumed_chain_state_size = 0; + chainTxData = ChainTxData{ + 0, + 0, + 0, + }; LogPrintf("Signet with challenge %s\n", signet_challenge[0]); } @@ -288,7 +311,9 @@ public: consensus.signet_blocks = true; consensus.signet_challenge.assign(bin.begin(), bin.end()); consensus.nSubsidyHalvingInterval = 210000; + consensus.BIP16Exception = uint256{}; consensus.BIP34Height = 1; + consensus.BIP34Hash = uint256{}; consensus.BIP65Height = 1; consensus.BIP66Height = 1; consensus.CSVHeight = 1; @@ -297,24 +322,27 @@ public: consensus.nPowTargetSpacing = 10 * 60; consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; - consensus.nRuleChangeActivationThreshold = 1916; - consensus.nMinerConfirmationWindow = 2016; + consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 + consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing + consensus.MinBIP9WarningHeight = 0; consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000"); consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008 + // Activation of Taproot (BIPs 340-342) + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + // message start is defined as the first 4 bytes of the sha256d of the block script CHashWriter h(SER_DISK, 0); h << consensus.signet_challenge; uint256 hash = h.GetHash(); memcpy(pchMessageStart, hash.begin(), 4); - LogPrintf("Signet derived magic (message start): %s\n", HexStr({pchMessageStart, pchMessageStart + 4})); nDefaultPort = 38333; nPruneAfterHeight = 1000; - m_assumed_blockchain_size = 0; - m_assumed_chain_state_size = 0; genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN); consensus.hashGenesisBlock = genesis.GetHash(); @@ -335,12 +363,6 @@ public: fRequireStandard = true; m_is_test_chain = true; m_is_mockable_chain = false; - - chainTxData = ChainTxData{ - 0, - 0, - 0 - }; } }; @@ -372,12 +394,12 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - // The best chain should have at least this much work. - consensus.nMinimumChainWork = uint256S("0x00"); - - // By default assume that the signatures in ancestors of this block are valid. - consensus.defaultAssumeValid = uint256S("0x00"); + consensus.nMinimumChainWork = uint256{}; + consensus.defaultAssumeValid = uint256{}; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; @@ -485,16 +507,16 @@ const CChainParams &Params() { return *globalChainParams; } -std::unique_ptr<const CChainParams> CreateChainParams(const std::string& chain) +std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const std::string& chain) { if (chain == CBaseChainParams::MAIN) { return std::unique_ptr<CChainParams>(new CMainParams()); } else if (chain == CBaseChainParams::TESTNET) { return std::unique_ptr<CChainParams>(new CTestNetParams()); } else if (chain == CBaseChainParams::SIGNET) { - return std::unique_ptr<CChainParams>(new SigNetParams(gArgs)); + return std::unique_ptr<CChainParams>(new SigNetParams(args)); } else if (chain == CBaseChainParams::REGTEST) { - return std::unique_ptr<CChainParams>(new CRegTestParams(gArgs)); + return std::unique_ptr<CChainParams>(new CRegTestParams(args)); } throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); } @@ -502,5 +524,5 @@ std::unique_ptr<const CChainParams> CreateChainParams(const std::string& chain) void SelectParams(const std::string& network) { SelectBaseParams(network); - globalChainParams = CreateChainParams(network); + globalChainParams = CreateChainParams(gArgs, network); } diff --git a/src/chainparams.h b/src/chainparams.h index 7aa999fb75..d8b25c7220 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -119,7 +119,7 @@ protected: * @returns a CChainParams* of the chosen chain. * @throws a std::runtime_error if the chain is not supported. */ -std::unique_ptr<const CChainParams> CreateChainParams(const std::string& chain); +std::unique_ptr<const CChainParams> CreateChainParams(const ArgsManager& args, const std::string& chain); /** * Return the currently selected parameters. This won't change after app diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index f19e72e9ab..2c517b58f8 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -37,16 +37,20 @@ const CBaseChainParams& BaseParams() return *globalChainBaseParams; } +/** + * Port numbers for incoming Tor connections (8334, 18334, 38334, 18445) have + * been chosen arbitrarily to keep ranges of used ports tight. + */ std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain) { if (chain == CBaseChainParams::MAIN) { - return MakeUnique<CBaseChainParams>("", 8332); + return MakeUnique<CBaseChainParams>("", 8332, 8334); } else if (chain == CBaseChainParams::TESTNET) { - return MakeUnique<CBaseChainParams>("testnet3", 18332); + return MakeUnique<CBaseChainParams>("testnet3", 18332, 18334); } else if (chain == CBaseChainParams::SIGNET) { - return MakeUnique<CBaseChainParams>("signet", 38332); + return MakeUnique<CBaseChainParams>("signet", 38332, 38334); } else if (chain == CBaseChainParams::REGTEST) { - return MakeUnique<CBaseChainParams>("regtest", 18443); + return MakeUnique<CBaseChainParams>("regtest", 18443, 18445); } throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); } diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index 9852446b3c..d593cff722 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -26,13 +26,16 @@ public: ///@} const std::string& DataDir() const { return strDataDir; } - int RPCPort() const { return nRPCPort; } + uint16_t RPCPort() const { return m_rpc_port; } + uint16_t OnionServiceTargetPort() const { return m_onion_service_target_port; } CBaseChainParams() = delete; - CBaseChainParams(const std::string& data_dir, int rpc_port) : nRPCPort(rpc_port), strDataDir(data_dir) {} + CBaseChainParams(const std::string& data_dir, uint16_t rpc_port, uint16_t onion_service_target_port) + : m_rpc_port(rpc_port), m_onion_service_target_port(onion_service_target_port), strDataDir(data_dir) {} private: - int nRPCPort; + const uint16_t m_rpc_port; + const uint16_t m_onion_service_target_port; std::string strDataDir; }; diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 2aca18c188..3dfbae33bc 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -9,752 +9,1169 @@ */ static SeedSpec6 pnSeed6_main[] = { {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x27,0xad,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x39,0x26,0x85}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x5c,0x27,0x27}, 15426}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0xe6,0x92,0xa3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x02,0x4a,0xaf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x08,0x12,0x1d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x27,0xde,0x27}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x03,0x0e,0xa8,0xc9}, 48333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x04,0x24,0x70,0x2c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x08,0x12,0x1f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x0e,0xc8,0xa7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x38,0x14,0x02}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x66,0x92,0x63}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x67,0x89,0x92}, 9333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x80,0x57,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x95,0xfa,0x4c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xb6,0x27,0xc8}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x85,0x41,0x52}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbb,0x37,0xf2}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbc,0x3e,0x18}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbc,0x3e,0x21}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbc,0xbb,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbd,0x99,0xb3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xc6,0x14,0xe3}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xc7,0x85,0xc1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xfe,0x52,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0d,0xed,0x93,0x0f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x08,0x26,0x59,0x98}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0d,0xe7,0x14,0xf9}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0x1b,0x4f,0x11}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x14,0xb8,0x0f,0x74}, 8433}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x11,0xa0,0x9f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x1c,0xcd,0x61}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x6a,0xfc,0xe6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xaf,0x00,0xca}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xaf,0x00,0xd4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xf1,0xfa,0xfc}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xf5,0x18,0x9a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x4c,0x7a,0x6c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x60,0x49,0x9c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x60,0x7d,0x39}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x9b,0xc4,0x1b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xcb,0x58,0xa7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe9,0xf5,0xbc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xf6,0x1f,0xcd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x06,0x62,0x5e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x0e,0xc9,0x9c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x19,0xf1,0xe0}, 8335}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x2b,0x8c,0xbe}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x56,0xb8,0x42}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x74,0xf6,0x09}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x8d,0x22,0xa6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x9b,0xc4,0xf6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x9d,0x82,0xde}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xbc,0xb0,0xff}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xed,0x46,0x35}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1b,0x7c,0x04,0x43}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x11,0x46,0x50}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x15,0x08,0x20}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x2d,0x76,0x0a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x84,0x11,0x38}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x86,0x79,0xdf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xad,0x30,0x3d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x22,0xcb,0xa9,0xac}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xb2,0x1f,0x04}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xb9,0xac,0x3e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xce,0xab,0x59}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xd0,0x57,0xcb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x3d,0xdb,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x8f,0xd2,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x8f,0xd3,0x53}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xeb,0x80,0x0b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xfc,0xbe,0x58}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x26,0x66,0x86,0x55}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x27,0x6d,0x00,0x96}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2a,0xc8,0x48,0xcd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2b,0xe5,0x84,0x66}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x20,0xd6,0xb7,0x72}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0x89,0xec,0x20}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xb9,0x91,0x69}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xd1,0x33,0xd4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0xf5,0xaf,0x4c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x74,0x5f,0x29}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x8f,0x09,0x6b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x8f,0x74,0x2b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xbf,0xf4,0x95}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xd3,0x4e,0xfd}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xdd,0xd1,0xde}, 24333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xe4,0x5c,0x6e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2b,0xe1,0x3e,0x6b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2b,0xe1,0x9d,0x98}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x24,0xb8,0x06}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x3a,0x31,0x23}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4c,0x12,0x2f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x73,0xef,0x6c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x17,0x57,0xda}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x30,0xa8,0x10}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x55,0x55,0x08}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x55,0x55,0x09}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x81,0xb4,0xd6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x95,0x4e,0x80}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x97,0x7d,0xda}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x9a,0xff,0x2e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x9b,0x9d,0xef}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x1c,0x84,0x22}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x1c,0xcc,0x15}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x20,0x32,0x62}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x24,0x61,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x26,0xed,0x6c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x27,0x81,0x52}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa0,0xc3,0x79}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x3b,0x0d,0x23}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x80,0x28,0xad}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x80,0x8c,0xc1}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x92,0xf8,0x59}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0xa2,0x2d}, 20001}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xbc,0x1e,0x76}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xbc,0x0f,0x06}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe5,0xa5,0x8e}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe5,0xee,0xbb}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xf9,0x53,0x52}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xfe,0xd9,0xa9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x34,0x72,0xc6}, 8885}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x58,0x54,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x6c,0x1d,0x98}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x6c,0x1e,0xa5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x4a,0xbf,0x22}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x73,0x35,0xa3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xbb,0x1a,0x87}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xde,0x67,0xea}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x31,0xf5,0x32,0xe0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x35,0xfa,0xa2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0xe1,0xc6,0x43}, 6000}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0xfd,0x05,0x63}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x31,0xe8,0x52,0x4c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x31,0xf7,0xd7,0x2b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x02,0x0d,0xa6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x22,0x27,0x48}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x2d,0xe8,0xbd}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x44,0x68,0x5c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x33,0x44,0x24,0x39}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x33,0x9a,0x3c,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xf2,0x11,0x07}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x92,0xde,0xc6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x34,0xa9,0xee,0x42}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xc5,0x1e,0xdf}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xe3,0x42,0x39}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x9e,0x00,0x56}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3b,0x95,0xcd,0xc5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3c,0xfb,0x81,0x3d}, 8336}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x9b,0x05,0x04}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x2d,0x04,0x8b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x61,0xf4,0xf2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6d,0x12,0x17}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x85,0xc2,0x9c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x8a,0x00,0xd9}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0xab,0x87,0xf2}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0xe5,0xd0,0x9e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3c,0xf4,0x6d,0x13}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x26,0x4b,0xd0}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x4a,0x8f,0x0b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x50,0xe3,0x31}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x98,0x3a,0x10}, 9421}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0x8f,0x22,0x62}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xd3,0x6f,0x7a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xe0,0xf9,0xf0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0xb6,0x77,0x24}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0xe5,0x69,0x6f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0x1b,0x68,0x70}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0xb7,0x4c,0x49}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x97,0xf2,0x9a}, 8335}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xce,0x0d,0x46}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0xa7,0xc7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xea,0xbc,0xa0}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xfb,0x36,0xa3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xe3,0x74,0xa2}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0x13,0x9b,0x52}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0x5f,0x31,0x66}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x12,0xac,0x15}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xf0,0xed,0x9b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xf0,0xed,0xac}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xcd,0x8c,0x91}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xd2,0xe4,0xcb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xdd,0xc1,0x37}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xde,0x83,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x6e,0x5a,0x6f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x8e,0x21,0x24}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xc7,0x9d,0xb7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xca,0x80,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xce,0x15,0x90}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x1e,0xd7,0x2a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x37,0xea,0x4a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x3b,0x12,0x16}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x91,0x7a,0xa0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0xaf,0x31,0xe6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x40,0x30,0x29}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x21,0xe8,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x49,0x12,0x20}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x92,0x72,0x6f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x3b,0x12,0xce}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x40,0x21,0x47}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x77,0xc1,0x09}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0xd1,0x17,0x48}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x7b,0x7d,0xed}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0xb9,0x38,0x88}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x26,0x5a,0xeb}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x0c,0x49,0x46}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x35,0x86,0xb6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x7e,0x61,0x63}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x53,0x7e,0x96}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x54,0x80,0x9e}, 9333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x62,0xf2,0x61}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xe1,0x07,0x50}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xea,0xb6,0x27}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xfa,0xb8,0x39}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x53,0x67,0x4f}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x76,0x89,0x77}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x85,0x64,0x4a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0xd7,0xdb,0xd6}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0xdc,0xff,0xbe}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x2d,0x33,0x29}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x9e,0x27,0xe7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x0b,0x11,0xbb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x54,0x4f,0xd3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xa7,0xb3,0x4b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x35,0x9e,0x89}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x77,0xe5,0x6a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x35,0x35,0xc4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x46,0x10,0xf5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x69,0x57,0x61}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x78,0x71,0x45}, 8433}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x78,0x7a,0x16}, 8433}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x78,0x7a,0x72}, 8433}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xa3,0x88,0x88}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xdc,0x8c,0x4a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xa6,0x53,0xa7}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xf7,0xb2,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x80,0x3e,0x34}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x80,0x4f,0x16}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x1b,0x8b,0x0d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x3f,0x1c,0x92}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x53,0x67,0x04}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x8d,0x7b,0x63}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x8f,0xd6,0xdf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x9f,0x63,0x55}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x4d,0x21,0x83}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x78,0x46,0x2f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x8e,0x81,0xda}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xaf,0x7d,0xd2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x2f,0x9c,0x2b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x4d,0x85,0x1e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x65,0x01,0x19}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x75,0xc0,0xe5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x85,0xe4,0x37}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x92,0x15,0xa3}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x59,0xcb,0xac}, 8001}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x5d,0xd5,0xf6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x6f,0x8e,0xd5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x93,0x52,0xa5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xd3,0xbf,0x0b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xd3,0xf5,0x97}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xc0,0x62,0x6e}, 8334}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xe5,0x1c,0x3c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xe5,0xa8,0x01}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xe8,0xf7,0xd2}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xf2,0x27,0x4c}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xfd,0x5e,0xfc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x04,0x66,0x45}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x00,0xc6,0x19}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x0d,0x54}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x0a,0xcd,0x15}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x75,0xe1,0xf5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xb1,0x9d,0x51}, 39993}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xeb,0xb9,0x96}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x87,0x89,0xe1}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xab,0x16,0x8f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xbf,0xe9,0x86}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xe8,0x4e,0x4b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xf2,0x5b,0x17}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x1d,0x3a,0x6d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x75,0xa6,0x4d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x76,0x14,0x25}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x92,0x32,0x8f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x92,0x99,0x82}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x88,0x63,0x16}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x95,0x61,0x19}, 17567}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xa9,0x82,0x3d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xb5,0xb3,0xe6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xb5,0xda,0xe5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xa5,0x13,0x30}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc2,0x99,0xe9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc3,0xed,0xfd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc5,0xda,0x61}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc5,0xd7,0x7d}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc7,0x66,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc7,0x66,0x85}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xca,0xc5,0xe0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xd9,0xf5,0x07}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x6f,0x88}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x59,0x1b,0x32}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x59,0xfa,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xa7,0x1b,0x04}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xd0,0xfe,0xb6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc8,0xcd,0x1e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xca,0x44,0xe7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x80,0x1f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xe4,0x06,0x83}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x55,0x8b,0x5e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x63,0xf5,0x14}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x89,0x29,0x0a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xae,0xd1,0x57}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xd9,0x08,0x1f}, 44420}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xdd,0xd3,0x74}, 8335}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xf3,0x3b,0x29}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xfb,0xf1,0x00}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x26,0x03,0xf9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x28,0x5e,0xaa}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x26,0xb9,0x7a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x5c,0x5c,0xf7}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xc0,0x10,0xea}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd1,0x09,0x17}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xea,0x60,0x73}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xf8,0x0e,0xd2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x77,0x53,0x19}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x90,0x77,0xde}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x91,0xee,0x5d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xc2,0x9e,0x7c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0x91,0x18}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0xf4,0x5f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd8,0x33,0x24}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xff,0xf9,0xa3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x19,0xff,0x93}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x46,0x9c,0xd1}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x91,0x8e,0x2e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xaa,0xe9,0x5f}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xb8,0x8a,0x6c}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xbe,0x00,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xca,0x0b,0x77}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xcc,0x60,0xcf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd0,0x45,0x0d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0x5a,0xa1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xf0,0xe9,0xdc}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xbf,0xc8,0x33}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xc0,0xbf,0x06}, 18500}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xc2,0xee,0x83}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xc3,0x36,0x6e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0xa1,0xfc}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0xb9,0x33}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xf1,0x6a,0xcb}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x0f,0x26,0x3d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x4c,0x07,0x84}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xf6,0xa8,0xfc}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x38,0xee,0xf7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x3d,0x5a,0xe6}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x4f,0x44,0x56}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x4f,0x5e,0xdd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x76,0x74,0xed}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x78,0x08,0x05}, 20008}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xde,0x16,0xff}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xe9,0xb5,0x92}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xf6,0x2e,0x84}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xf9,0xcf,0x59}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x56,0x74,0x8c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x56,0x74,0x8e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x58,0x0d,0xf9}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xf7,0x6f,0xde}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x54,0xde,0xfc}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x56,0xf3,0xf1}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x57,0x5d,0x34}, 1691}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x77,0xc5,0xc8}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x81,0xfd,0x5e}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x93,0xf4,0xfa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x96,0xe6,0x5f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xca,0xca,0xdd}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x03,0xc3}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd4,0x2c,0x21}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x19,0x50,0x2a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x1c,0x75,0x1f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd6,0x39,0x5f}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x6a,0xc7,0x26}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x8e,0x4b,0x3c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x6c,0x7e,0xe4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x73,0x78,0x2b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x85,0x44,0x41}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xbe,0x13,0xa2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xd4,0x09,0x60}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xd4,0x4b,0x06}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xf8,0xfa,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x5e,0x53,0x1a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xf8,0xac,0x0a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x92,0x99,0x15}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0xb6,0xa5,0x12}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xb9,0xc6,0xea}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x6a,0xbc,0xe5}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc1,0xed,0x74}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xcc,0x63,0xb2}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xcc,0x95,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd2,0x18,0x1e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd3,0x58,0x21}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd8,0x95,0x1c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xde,0x80,0x3b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x12,0xb4,0xe1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x35,0x59,0x7b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0xf0,0x45,0xc3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd6,0x46,0x3f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe4,0x98,0xec}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x0c,0x9a,0x73}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0xf9,0x8f,0x2c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0xff,0xb0,0x6d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x39,0x51,0xa2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x5a,0xc1,0xc3}, 8330}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x5a,0xcf,0x2e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x73,0x1a,0xba}, 20004}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x73,0xf0,0x1a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x0c,0x42,0x62}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x2e,0x36,0x04}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x73,0x14,0x82}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x7b,0xb4,0xa4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xaf,0xcc,0x79}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xb4,0xb2,0xd5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xbd,0x91,0xa9}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xf1,0xe4,0x66}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x13,0x07,0x37}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x13,0x80,0xcc}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x34,0x70,0xe3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x35,0x02,0xb5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x48,0x8f,0x1a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x67,0x78,0xad}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xed,0x40,0x8a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xed,0x50,0xcf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xf2,0xff,0x1f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x18,0x30,0x54}, 15426}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x2a,0x02,0x71}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x9a,0x60,0x82}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x9c,0xae,0xc9}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x9e,0xf6,0xb7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xb1,0xab,0x49}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xc7,0xb2,0xe9}, 8100}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xed,0x7d,0x1e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xf7,0x86,0x4d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x30,0xe4,0x2d}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x45,0xf9,0x3f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x4f,0x23,0x85}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x52,0x92,0x46}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x53,0x49,0x1f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x54,0xa4,0x2b}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x57,0xe2,0x38}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x5a,0x03,0xd2}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x6e,0xea,0x5d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x9c,0xfc,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd3,0xbd,0x03}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd9,0x09,0xcf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x09,0x50,0x6d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0xf5,0xda,0xf7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x68,0xce,0x03}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x1d,0xc3,0xcc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0xe7,0xc4,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x64,0xae,0x18}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xa3,0x47,0x7e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xa4,0x41,0xc2}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xae,0x42,0xd3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd3,0xae,0x89}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd8,0x0b,0x9c}, 8433}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x2f,0x72,0x6c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x54,0xe8,0x69}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x63,0xcd,0xf1}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x19,0xc1,0x72}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0x73,0x19,0x0d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x20,0x13,0xb8}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x64,0xae,0xf0}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x66,0x84,0xf5,0x10}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x0e,0xf4,0xbe}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x25,0xcd,0x2f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x3c,0x6d,0xb8}, 20008}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x4c,0x30,0x05}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x54,0x54,0xfa}, 8335}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x55,0xbe,0xda}, 20000}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x63,0xa8,0x64}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x63,0xa8,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xd6,0x92,0x56}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x63,0xa8,0x96}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x6d,0x65,0xd8}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x7a,0xf7,0x66}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x81,0x0d,0x2d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xc6,0xc0,0x0e}, 20008}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xe0,0x77,0x63}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xe7,0xbf,0x07}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xeb,0xe6,0xc4}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xab,0xf2,0x9b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc7,0xb8,0x0f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xf4,0xdf,0x97}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x69,0x1d,0x4c,0xc2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x2d,0x12}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xb4,0x4d,0x15}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x3a,0xfc,0x52}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xee,0xdc,0xc7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6a,0xa3,0x9e,0x7f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x29,0xb3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x9f,0x5d,0x67}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xb7,0x4d,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x48,0x53,0x7f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x09,0xaf,0x41}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x63,0x3f,0x9f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x6d,0x24,0x13}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x6e,0x51,0x5a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xad,0x70,0xe0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xca,0x6b,0x7d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xcd,0x6d,0x38}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xec,0x54,0x8d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xee,0x51,0x52}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x7b,0xd5,0x82}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x86,0xe8,0x51}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xa9,0x14,0xa8}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xc7,0xf1,0x94}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe5,0xd2,0x06}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xec,0x69,0x28}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xf8,0xce,0x0d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6f,0x28,0x04,0x67}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6f,0x5a,0x8c,0xd9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6f,0x5a,0x9e,0xd4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x70,0xd5,0x67,0x62}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6f,0x2a,0x4a,0x41}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6f,0x5a,0x8c,0xb3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x70,0xd7,0xcd,0xec}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x71,0x34,0x87,0x7d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x72,0x17,0xf6,0x89}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x2f,0x8d,0xfa}, 8885}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x46,0x6e,0x04}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x74,0x57,0x0f,0xf4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x74,0x22,0xbd,0x37}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0x67,0x7e,0x8c}, 28333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0xbd,0xbb,0xdb}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x03,0xd0,0xec}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x08,0x2f,0xe1}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0x11,0x97,0x3d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0xab,0x86,0x57}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x12,0xee,0x27}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x4e,0xdf,0xba}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x62,0xcd,0x66}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0x19,0x18,0x1e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0xf1,0x22,0x0a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x62,0xcd,0x64}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7a,0x70,0x94,0x99}, 8339}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7a,0x74,0x2a,0x8c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0xa0,0x77,0x5d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7c,0xd9,0xeb,0xb4}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7d,0xec,0xd7,0x85}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x81,0x0d,0xbd,0xd4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x81,0x61,0xf3,0x12}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x82,0xb9,0x4d,0x69}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x72,0x0a,0xe9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0xbc,0x28,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x84,0xf9,0xef,0xa3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0x13,0xba,0xc3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0xf9,0xbb,0x61}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x90,0xd7,0xdb}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0xbc,0x28,0xbf}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0xc1,0xdc,0x0f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x87,0x17,0x7c,0xef}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x21,0xb9,0x20}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x88,0x38,0xaa,0x60}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0xe2,0x22,0x2e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0xe5,0x1a,0x2a}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8b,0x09,0xf9,0xea}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0x65,0x08,0x24}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0x59,0x79,0xcf}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0xb0,0xe0,0x68}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x02,0x45,0xe0}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x22,0xa1,0x41}, 18333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x93,0xfd,0x46,0xd0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0x42,0x32,0x52}, 8335}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x99,0x5c,0x7f,0xd8}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x99,0x78,0x73,0x0f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9a,0x34,0x62,0x02}, 8444}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9b,0x04,0x74,0xa9}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x5b,0x74,0x2c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x89,0x1d,0xb5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0x42,0x32,0x32}, 8335}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0x48,0x96,0xe7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0xaa,0xd4,0x2c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0xa7,0x63,0xbe}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9a,0x5c,0x10,0xbf}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9a,0xdd,0x1b,0x15}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9c,0x13,0x13,0x5a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9c,0x22,0xb2,0x8a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0x0d,0x3d,0x42}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0x0d,0x3d,0x43}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9c,0xf1,0x05,0xbe}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0x0d,0x3d,0x4c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0x0d,0x3d,0x50}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0xe6,0xa6,0x62}, 14391}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x4b,0xcb,0x02}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0xb5,0x7d,0x96}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0xb5,0xe2,0x21}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9f,0x64,0xf2,0xfe}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9f,0x64,0xf8,0xea}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9f,0xfd,0x62,0xd1}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9f,0x8a,0x57,0x12}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa0,0x10,0x00,0x1e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa0,0x14,0x91,0x3e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0x00,0xe3,0x36}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0x00,0xe3,0x38}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0x3e,0x12,0xe2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0x3e,0x1a,0xda}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x58,0xae}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x01,0xe9}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf3,0xaf,0x56}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf4,0x50,0xd0}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xfa,0xbc,0x57}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xfa,0xbd,0x35}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0x9e,0xca,0x70}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0xac,0xb5,0xbf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa6,0x3e,0x64,0x37}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa7,0x72,0x23,0x0c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0x3e,0xa7,0xd1}, 8200}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0xeb,0x4a,0x6e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0xeb,0x5a,0xbc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaa,0xf9,0x25,0xf3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x63,0x78,0x71}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x15,0xda,0x5f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x33,0xb1,0x02}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x5f,0x48,0xea}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0x9e,0xf3,0xe6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa5,0x49,0x3e,0x1f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa6,0x3e,0x52,0x67}, 32771}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa6,0x46,0x5e,0x6a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa7,0x56,0x5a,0xef}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa9,0x2c,0x22,0xcb}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x5d,0x65,0x49}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x69,0x07,0x2f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x17,0x67,0x1e}, 8000}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x35,0x4f,0x06}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x46,0x0c,0x56}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x59,0x1c,0x89}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xb0,0xb8,0x36}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd0,0x80,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd1,0x2c,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xe7,0x39,0xc2}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xfe,0xcc,0x45}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xff,0xcc,0x7c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x41,0x87,0x3c}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x5e,0x9b,0xe0}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x73,0x78,0xba}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x35,0xa0,0xaa}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x55,0xbc,0xd5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x72,0x66,0x29}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x72,0x7c,0x0c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x0a,0xe3,0x3b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x1f,0xe0,0xd6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x4a,0x88,0xed}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x63,0x02,0xcf}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x79,0x0e,0x9d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x7a,0x9d,0xad}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x7e,0x55,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xc6,0x78,0xc5}, 8334}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3d,0x8d,0xc6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x77,0xb7,0x22}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xea,0x1d,0xb8}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x6a,0xbf,0x02}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xa0,0xe4,0x09}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xbf,0xb6,0x03}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xd4,0xb9,0x99}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xf1,0x89,0xb7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb1,0x26,0xd7,0x49}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x10,0xde,0x92}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x84,0x02,0xf6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x8f,0xbf,0xab}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x94,0xac,0xd1}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x94,0xe2,0xb4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x96,0x60,0x2e}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xb6,0xe3,0x32}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xec,0x89,0x3f}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xff,0x2a,0x7e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb3,0x30,0xfb,0x29}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0x96,0x49,0x64}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0x2f,0xdc,0xf2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0xaa,0x8b,0x2f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0x96,0x34,0x25}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0x27,0x20,0x63}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0x30,0x4d,0x1a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0x34,0xdf,0x34}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb5,0xee,0x33,0x98}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb7,0x58,0xdf,0xd0}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb7,0x6e,0xdc,0xd2}, 30301}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb7,0xe6,0x5d,0x8b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x5f,0x3a,0xa4}, 8663}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x5f,0x3a,0xa6}, 8336}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0xa4,0x93,0x52}, 41333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x0f,0x5c,0x12}, 20993}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x3c,0xc7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x34,0x03,0xb9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x3d,0x8a,0x04}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0xab,0xd0,0x6d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0x27}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x19,0x30,0xb8}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x40,0x74,0x0f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x53,0x6e,0x35}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x53,0xd6,0x7b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x50,0xdb,0x84}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x55,0x03,0x8c}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x5f,0xdb,0x35}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x60,0x5e,0x18}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x66,0x47,0x06}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x8a,0x23,0xb7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x8c,0xfc,0xfd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x8f,0x91,0x71}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x6c,0xf4,0x29}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x86,0xe9,0x79}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x91,0x80,0x15}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x94,0x03,0xe3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x9d,0xa0,0xdc}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xa3,0x2c,0x2c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xb0,0xdd,0x20}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x99,0xc4,0xf0}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x9e,0x72,0xb8}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xa5,0xa8,0xc4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xb5,0xe6,0x4a}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xb9,0x1a,0x8d}, 8111}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xba,0xd0,0xa2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xc6,0x3a,0x2f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xc6,0x3b,0xb7}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xd7,0xe0,0x16}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xe8,0x1c,0xfe}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xef,0xec,0x74}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xbd,0x84,0xb2}, 57780}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xd3,0x3b,0x32}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xe9,0x94,0x92}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xee,0x81,0x71}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xf9,0xc7,0x6a}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0xfb,0xa1,0x36}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbb,0xbd,0x99,0x88}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x25,0x18,0xbe}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x2a,0x28,0xea}, 18333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x41,0xd4,0x8a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x41,0xd4,0x9d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x3d,0x2e,0x24}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x44,0x2d,0x8f}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x7f,0xe5,0x69}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x83,0xb1,0x82}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x86,0x06,0x54}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x86,0x08,0x24}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x86,0x58,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x8a,0x11,0x5c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x96,0x9d,0x0b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xd0,0x6f,0x3e}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xe7,0xb1,0x95}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x02,0x91,0xb1}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x68,0xf9,0x2c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xd6,0x81,0x41}, 20012}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xe6,0xa8,0x72}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbd,0x22,0x0e,0x5d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbd,0xcf,0x2e,0x20}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0xd3,0xcc,0x44}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbf,0xd1,0x15,0xbc}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x03,0x0b,0x14}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x03,0x0b,0x18}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x22,0x38,0x3b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x03,0xb9,0xd2}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x41,0xaa,0x0f}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x41,0xaa,0x32}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x92,0x89,0x12}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xa6,0x2f,0x20}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xa9,0x5e,0x1d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x9d,0xca,0xb2}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xe3,0x50,0x53}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xfe,0x41,0x7e}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x0a,0xcb,0x17}, 8334}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x1d,0x39,0x04}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x19,0x06,0xce}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x2a,0x6e,0x1e}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x3a,0xc4,0xd4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x3b,0x29,0x0b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x54,0x74,0x16}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x6c,0x83,0x2b}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x94,0x47,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xa9,0xf4,0xbe}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x6a,0x1c,0x08}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xbd,0xbe,0x7b}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xc2,0xa3,0x23}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xc2,0xa3,0x35}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x05,0x9f,0xc5}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x0e,0xf6,0xcd}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x87,0x5c,0x60}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x24,0x5b,0xfd}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x7e,0x71,0x87}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x87,0x87,0x45}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x9e,0x5c,0x96}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0xbb,0xfb,0xa3}, 31239}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x38,0x3f,0x04}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x38,0x3f,0x05}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x38,0x3f,0x0a}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x43,0x8b,0x36}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x5f,0xe1,0x11}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x87,0xc2,0x08}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x9a,0x71,0x5a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xce,0x14,0x72}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xca,0xa9,0x95}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xce,0x69,0x2a}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xd1,0xf9,0xa4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xe0,0x74,0x14}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x01,0xe7,0x06}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0xfb,0x53,0x13}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x30,0x53,0x3a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x60,0x32,0xd3}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xbc,0xcc,0x19}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xc0,0x14,0xc9}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x4c,0xc2,0x07}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x57,0x74,0xd5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x1c,0xc2,0x52}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0xc8,0x2b,0xd7}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xb6,0xb8,0xcc}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xf7,0x07,0xd0}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xf7,0xf9,0xbc}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x07,0xfc,0x76}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x14,0xba,0xfe}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x53,0xa6,0x88}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x37,0x57,0x2d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x4f,0xa7,0x41}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x6c,0xd3,0x87}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0xa9,0x66,0x49}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x82,0x30,0x75}, 8885}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x84,0x5f,0x0a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x0e,0xf5,0xb4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x98,0xcb,0x62}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcd,0xd1,0xa2,0x62}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xce,0xdd,0xb2,0x95}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x97,0xa6,0x7b}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x5d,0x71,0x6c}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x6f,0xf1,0xc3}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xce,0x7c,0x95,0x42}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0x73,0x66,0x62}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xe5,0x2e,0x96}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x4c,0xfc,0xc6}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x64,0x0d,0x38}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x64,0xb2,0xaf}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x6e,0x63,0x69}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x06,0xd2,0xb3}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x85,0xdc,0x4a}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x97,0xed,0x47}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd3,0x95,0xaa,0x1f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x33,0x84,0xe2}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0xf1,0x46,0xd5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x15,0x0f,0x16}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x88,0x53,0x08}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xe3,0x98,0x6c}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xfe,0x17,0x74}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x6c,0xec,0xb4}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xc2,0xa5,0x62}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x8d,0x39,0x39}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd3,0x1b,0x93,0x43}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x22,0xe1,0x76}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x59,0xad,0xd8}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x63,0xe2,0x24}, 9020}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0xed,0x60,0x62}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x59,0x83,0x35}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x26,0x81,0xa4}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x86,0xa5,0x37}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x92,0xfb,0x08}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xbd,0xbe,0x5f}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xe2,0x80,0xbd}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xec,0xa4,0x52}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x10,0xb9,0xa5}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x15,0x18,0x92}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x13,0xd8,0xd2}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x1a,0x20,0x0a}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x40,0x2f,0x8a}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x40,0x85,0xdc}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x5c,0x37,0xf6}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xac,0xf4,0x09}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xda,0x4b,0x8c,0x2d}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdb,0x4b,0x7a,0x2f}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdc,0xe9,0x8a,0x82}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdd,0x82,0x1d,0xe6}, 18421}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xde,0x7a,0x31,0x28}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xde,0xba,0xa9,0x01}, 8333}, - {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xde,0xde,0x2b,0x1d}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xda,0x1f,0x71,0xf5}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xda,0xff,0xf2,0x72}, 8333}, + {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdc,0x85,0x27,0x3d}, 8333}, {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdf,0x10,0x1e,0xaf}, 8333}, + {{0x20,0x01,0x19,0xf0,0x60,0x01,0x30,0x6f,0x0e,0xc4,0x7a,0xff,0xfe,0x8f,0x66,0xec}, 8333}, {{0x20,0x01,0x1b,0xc0,0x00,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x01}, 8333}, {{0x20,0x01,0x1c,0x02,0x2f,0x18,0x0d,0x00,0xb6,0x2e,0x99,0xff,0xfe,0x49,0xd4,0x92}, 8333}, - {{0x20,0x01,0x02,0x50,0x02,0x00,0x00,0x07,0xd6,0xa9,0xfc,0xf4,0xe7,0x8d,0x2d,0x82}, 8333}, - {{0x20,0x01,0x41,0xc9,0x00,0x01,0x04,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x31}, 8333}, - {{0x20,0x01,0x41,0xd0,0x10,0x04,0x19,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, - {{0x20,0x01,0x44,0xb8,0x41,0x95,0x18,0x01,0x5c,0x73,0x5d,0x67,0xd2,0xa6,0x99,0x10}, 8333}, - {{0x20,0x01,0x04,0x70,0x88,0xff,0x00,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, + {{0x20,0x01,0x41,0x00,0x00,0x00,0x00,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93}, 8333}, + {{0x20,0x01,0x41,0x00,0x00,0x00,0x00,0x64,0xdc,0xaf,0xaf,0xff,0xfe,0x00,0x67,0x07}, 8333}, {{0x20,0x01,0x04,0x70,0x00,0x0a,0x0c,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x48,0x00,0x78,0x21,0x01,0x01,0xbe,0x76,0x4e,0xff,0xfe,0x04,0x9f,0x50}, 8333}, - {{0x20,0x01,0x48,0x01,0x78,0x19,0x00,0x74,0xb7,0x45,0xb9,0xd5,0xff,0x10,0xaa,0xec}, 8333}, - {{0x20,0x01,0x48,0xd0,0x00,0x01,0x21,0x63,0x00,0x00,0x00,0xff,0xfe,0xbe,0x5a,0x80}, 8333}, + {{0x20,0x01,0x48,0x01,0x78,0x19,0x00,0x74,0xb7,0x45,0xb9,0xd5,0xff,0x10,0xa6,0x1a}, 8333}, {{0x20,0x01,0x4b,0xa0,0xff,0xfa,0x00,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93}, 8333}, + {{0x20,0x01,0x06,0x10,0x19,0x08,0xff,0x01,0xf8,0x16,0x3e,0xff,0xfe,0x33,0x2e,0x32}, 8333}, {{0x20,0x01,0x06,0x38,0xa0,0x00,0x41,0x40,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0x91}, 8333}, + {{0x20,0x01,0x06,0x48,0x28,0x00,0x01,0x31,0x4b,0x1f,0xf6,0xfc,0x20,0xf7,0xf9,0x9f}, 8333}, {{0x20,0x01,0x06,0x78,0x07,0xdc,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x06,0x78,0x00,0xec,0x00,0x01,0x02,0x50,0x56,0xff,0xfe,0xa7,0x47,0xe9}, 8333}, - {{0x20,0x01,0x06,0x7c,0x10,0xec,0x2a,0x49,0x80,0x00,0x00,0x00,0x00,0x00,0x10,0x82}, 8333}, + {{0x20,0x01,0x06,0x78,0x0c,0xc8,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x88}, 20008}, + {{0x20,0x01,0x06,0x7c,0x12,0x20,0x08,0x0c,0x00,0x00,0x00,0x00,0x93,0xe5,0x0d,0xd2}, 8333}, + {{0x20,0x01,0x06,0x7c,0x12,0x20,0x08,0x0c,0xe5,0xdc,0xad,0x0c,0x92,0x89,0xc2,0x8f}, 8333}, {{0x20,0x01,0x06,0x7c,0x16,0xdc,0x12,0x01,0x50,0x54,0x00,0xff,0xfe,0x17,0x4d,0xac}, 8333}, - {{0x20,0x01,0x06,0x7c,0x21,0xec,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a}, 8333}, + {{0x20,0x01,0x06,0x7c,0x23,0x54,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22}, 8333}, {{0x20,0x01,0x06,0x7c,0x26,0xb4,0x00,0x12,0x7a,0xe3,0xb5,0xff,0xfe,0x04,0x6f,0x9c}, 8333}, - {{0x20,0x01,0x06,0x7c,0x2d,0xb8,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45}, 8333}, - {{0x20,0x01,0x07,0x00,0x03,0x00,0x15,0x13,0x29,0xc7,0x24,0x30,0x19,0x0e,0xab,0x59}, 8333}, + {{0x20,0x01,0x06,0x7c,0x02,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0xfa}, 8333}, {{0x20,0x01,0x07,0x18,0x08,0x01,0x03,0x11,0x50,0x54,0x00,0xff,0xfe,0x19,0xc4,0x83}, 8333}, - {{0x20,0x01,0x08,0x18,0xe2,0x45,0xf8,0x00,0x04,0xdf,0x2b,0xdf,0xec,0xf5,0xeb,0x60}, 8333}, + {{0x20,0x01,0x08,0xd8,0x08,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x99,0x03,0xc1}, 8333}, {{0x20,0x01,0x08,0xf1,0x14,0x04,0x37,0x00,0x8e,0x49,0x71,0x5a,0x2e,0x09,0xb6,0x34}, 9444}, - {{0x20,0x01,0x0b,0xa8,0x01,0xf1,0xf0,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x20,0x01,0x0b,0xb8,0x40,0x08,0x00,0x20,0x64,0x8c,0x5e,0xff,0xfe,0x74,0x0c,0xe4}, 8333}, - {{0x20,0x01,0x0d,0xa8,0xd8,0x00,0x08,0x21,0xa7,0xd5,0xf5,0xa7,0x53,0x0d,0xb7,0x1e}, 8333}, + {{0x20,0x01,0x0b,0x07,0x5d,0x29,0x99,0xa5,0x19,0x4b,0x38,0x74,0xd6,0x5e,0xa9,0x0d}, 8333}, + {{0x20,0x01,0x0b,0xa8,0x01,0xf1,0xf0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, + {{0x20,0x01,0x0b,0xc8,0x12,0x00,0x00,0x00,0xda,0xc4,0x97,0xff,0xfe,0x2a,0x35,0x54}, 20008}, + {{0x20,0x01,0x0d,0xa8,0x10,0x0d,0x00,0x22,0x10,0xfa,0xd8,0x5f,0x10,0xf2,0x21,0xfd}, 8333}, + {{0x20,0x01,0x0d,0xa8,0x80,0x01,0x7a,0x39,0xf0,0x35,0x00,0x7d,0xb9,0x9f,0xeb,0x79}, 8333}, {{0x20,0x01,0x0e,0x42,0x01,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30}, 8333}, - {{0x20,0x01,0x0e,0x68,0x74,0x00,0x00,0x02,0x68,0x54,0x41,0x9e,0x22,0x1c,0x82,0xf3}, 8333}, - {{0x20,0x02,0xb6,0x10,0x1c,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x10,0x1c,0xa3}, 8333}, - {{0x20,0x02,0xb6,0xff,0x3d,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0xff,0x3d,0xca}, 28364}, - {{0x24,0x00,0x26,0x51,0x42,0xe0,0x33,0x00,0x40,0xb4,0x57,0x6d,0xd1,0x4c,0x65,0xd4}, 8333}, + {{0x24,0x00,0x24,0x12,0x01,0x03,0xc9,0x00,0x08,0x25,0x8f,0x20,0xea,0xff,0x65,0xc2}, 8333}, {{0x24,0x00,0x40,0x52,0x0e,0x20,0x4f,0x00,0x69,0xfe,0xbb,0x33,0x7b,0x1c,0xa1,0xca}, 8333}, - {{0x24,0x01,0x25,0x00,0x02,0x03,0x01,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15}, 8333}, + {{0x24,0x01,0x18,0x00,0x78,0x00,0x01,0x05,0xbe,0x76,0x4e,0xff,0xfe,0x1c,0x0b,0x35}, 8333}, {{0x24,0x01,0x39,0x00,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x24,0x01,0xa4,0x00,0x32,0x00,0x56,0x00,0x14,0xee,0xf3,0x61,0x4b,0xdc,0x1f,0x7c}, 8333}, + {{0x24,0x01,0xb1,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x01,0x50}, 8333}, {{0x24,0x01,0xd0,0x02,0x44,0x02,0x00,0x00,0x8f,0x28,0x59,0x1a,0x6e,0xa0,0xc6,0x83}, 8333}, - {{0x24,0x02,0xcb,0x40,0x10,0x00,0x05,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xde,0xad}, 8333}, + {{0x24,0x03,0x62,0x00,0x88,0x21,0x3d,0x68,0x19,0x5b,0x87,0xe9,0x68,0x19,0xd5,0xc8}, 8333}, + {{0x24,0x05,0x65,0x80,0x21,0x40,0x3a,0x00,0xc2,0x8c,0x09,0x83,0x36,0x4b,0x5d,0x70}, 8333}, + {{0x24,0x05,0x98,0x00,0xb9,0x11,0xa1,0x8a,0x58,0xeb,0xcd,0x3c,0x9d,0x82,0xea,0x4a}, 8333}, {{0x24,0x05,0xaa,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40}, 8333}, {{0x24,0x09,0x00,0x10,0xca,0x20,0x1d,0xf0,0x02,0x24,0xe8,0xff,0xfe,0x1f,0x60,0xd9}, 8333}, - {{0x24,0x09,0x8a,0x15,0x4a,0x1a,0x28,0x30,0x72,0x85,0xc2,0xff,0xfe,0x70,0x60,0xa4}, 8333}, - {{0x24,0x09,0x8a,0x1e,0x69,0x38,0xd2,0xc0,0x02,0xe0,0x70,0xff,0xfe,0x86,0xcb,0x59}, 8333}, - {{0x24,0x09,0x8a,0x28,0x04,0x21,0x25,0x80,0x02,0xe0,0x70,0xff,0xfe,0x8b,0x01,0x3e}, 8333}, - {{0x24,0x09,0x8a,0x28,0x04,0x21,0x27,0x70,0x02,0xe0,0x70,0xff,0xfe,0x87,0xfe,0xcb}, 8333}, + {{0x24,0x09,0x8a,0x1e,0xa9,0xaf,0x36,0x60,0x1c,0x5a,0x5b,0x6b,0x8a,0x2d,0x98,0x48}, 8333}, + {{0x24,0x09,0x8a,0x1e,0xa9,0xaf,0x36,0x60,0x04,0x04,0x39,0xba,0x88,0xf2,0xe8,0xdf}, 8333}, + {{0x24,0x0b,0x00,0x10,0x91,0x41,0x04,0x00,0x49,0xb4,0x3a,0x2e,0x01,0xe5,0x08,0x4c}, 8333}, + {{0x24,0x0d,0x00,0x1a,0x07,0x59,0x60,0x00,0xa7,0xb1,0x45,0x1a,0x88,0x74,0xe1,0xac}, 8333}, {{0x24,0x0d,0x00,0x1a,0x07,0x59,0x60,0x00,0xdd,0xab,0x31,0x41,0x4d,0xa0,0x88,0x78}, 8333}, - {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xcd,0x1b,0x95}, 8333}, - {{0x26,0x00,0x6c,0x40,0x79,0x80,0x00,0x27,0x02,0x0a,0xf7,0xff,0xfe,0x69,0xf4,0xd5}, 8333}, - {{0x26,0x02,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc5,0xb8,0x44}, 8333}, - {{0x26,0x04,0x2d,0x80,0xc8,0x08,0x85,0x7b,0x08,0xd6,0x9e,0x1c,0x71,0x31,0x4b,0xea}, 8333}, + {{0x26,0x00,0x88,0x05,0x24,0x00,0x01,0x4e,0x12,0xdd,0xb1,0xff,0xfe,0xf2,0x30,0x13}, 8333}, + {{0x26,0x01,0x06,0x02,0x8d,0x80,0x0b,0x63,0xdc,0x3e,0x24,0xff,0xfe,0x92,0x05,0xeb}, 8333}, + {{0x26,0x02,0xff,0xb6,0x00,0x04,0x27,0x98,0xf8,0x16,0x3e,0xff,0xfe,0x2f,0x54,0x41}, 8333}, + {{0x26,0x02,0xff,0xb6,0x00,0x04,0x73,0x9e,0xf8,0x16,0x3e,0xff,0xfe,0x00,0xc2,0xb3}, 8333}, + {{0x26,0x02,0xff,0xb8,0x00,0x00,0x00,0x00,0x02,0x08,0x00,0x72,0x00,0x57,0x02,0x00}, 8333}, + {{0x26,0x04,0x13,0x80,0x41,0x11,0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, {{0x26,0x04,0x43,0x00,0x00,0x0a,0x00,0x2e,0x02,0x1b,0x21,0xff,0xfe,0x11,0x03,0x92}, 8333}, + {{0x26,0x04,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x06}, 8112}, + {{0x26,0x04,0x55,0x00,0x70,0x6a,0x40,0x00,0xfc,0x79,0xb9,0xbb,0x01,0xd7,0xc3,0x25}, 8333}, {{0x26,0x04,0x55,0x00,0xc1,0x34,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xfc}, 32797}, - {{0x26,0x04,0x55,0x00,0xc2,0xa3,0x7b,0x00,0x0c,0xc6,0x37,0x3b,0x44,0xa8,0xca,0xa4}, 8333}, - {{0x26,0x04,0x60,0x00,0x6e,0x85,0x4a,0x01,0xa8,0x2d,0xf9,0xff,0xfe,0xf5,0x28,0xb9}, 8333}, - {{0x26,0x04,0x77,0x80,0x03,0x03,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80}, 8333}, + {{0x26,0x04,0x68,0x00,0x5e,0x11,0x01,0x62,0x5c,0x8f,0xd2,0xff,0xfe,0x26,0x14,0x6f}, 8333}, {{0x26,0x05,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50}, 8333}, - {{0x26,0x05,0x98,0x80,0x00,0x00,0x07,0x77,0x02,0x25,0x90,0xff,0xfe,0xfc,0x89,0x58}, 8333}, + {{0x26,0x05,0x64,0x00,0x00,0x20,0x13,0xbf,0xdf,0x1d,0x18,0x1c,0x83,0xbb,0x22,0xe8}, 8333}, {{0x26,0x05,0xae,0x00,0x02,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x03}, 8333}, {{0x26,0x05,0xc0,0x00,0x2a,0x0a,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02}, 8333}, - {{0x26,0x05,0xe0,0x00,0x11,0x27,0x08,0xfc,0xec,0x63,0xa1,0x91,0x32,0xc2,0x63,0x3c}, 8333}, - {{0x26,0x05,0xe2,0x00,0xd2,0x02,0x03,0x00,0x02,0x0c,0x29,0xff,0xfe,0xf1,0x85,0xec}, 8333}, - {{0x26,0x05,0xf7,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x01,0x31,0x5b,0x54}, 8333}, - {{0x26,0x06,0xc6,0x80,0x00,0x00,0x00,0x0b,0x38,0x30,0x34,0xff,0xfe,0x66,0x66,0x63}, 8333}, - {{0x26,0x07,0x44,0x80,0x00,0x02,0x00,0x01,0x00,0x38,0x01,0x02,0x00,0x69,0x00,0x70}, 8333}, - {{0x26,0x07,0x92,0x80,0x00,0x0b,0x07,0x3b,0x02,0x50,0x56,0xff,0xfe,0x21,0x9c,0x2f}, 8333}, - {{0x26,0x07,0xf1,0x28,0x00,0x40,0x17,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x26,0x07,0xf1,0x88,0x00,0x00,0x00,0x04,0xee,0xf4,0xbb,0xff,0xfe,0xcc,0x66,0x68}, 8333}, - {{0x26,0x07,0xf2,0xc0,0xe1,0xe2,0x00,0x11,0x10,0x44,0x9b,0x7a,0xb8,0x1e,0x1d,0x74}, 8333}, + {{0x26,0x07,0xf2,0xc0,0xf0,0x0e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54}, 8333}, + {{0x26,0x07,0xf2,0xf8,0xad,0x40,0x0b,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, {{0x26,0x07,0xf4,0x70,0x00,0x08,0x10,0x48,0xae,0x1f,0x6b,0xff,0xfe,0x70,0x72,0x40}, 8333}, + {{0x26,0x07,0xff,0x28,0x80,0x0f,0x00,0x97,0x02,0x25,0x90,0xff,0xfe,0x75,0x11,0x10}, 8333}, {{0x26,0x20,0x01,0x1c,0x50,0x01,0x11,0x18,0xd2,0x67,0xe5,0xff,0xfe,0xe9,0xe6,0x73}, 8333}, - {{0x26,0x20,0x00,0x6e,0xa0,0x00,0x00,0x01,0x00,0x42,0x00,0x42,0x00,0x42,0x00,0x42}, 8333}, - {{0x28,0x04,0x01,0x4d,0xba,0xa7,0x96,0x74,0x02,0x1e,0x67,0xff,0xfe,0xa8,0xd7,0x99}, 8333}, - {{0x28,0x04,0x01,0x4d,0xba,0xa7,0x96,0x74,0x36,0x15,0x9e,0xff,0xfe,0x23,0xd6,0x10}, 8333}, - {{0x28,0x04,0x39,0xe8,0xff,0x85,0xa6,0x00,0x72,0x85,0xc2,0xff,0xfe,0xae,0x99,0x25}, 8333}, - {{0x28,0x04,0x0d,0x41,0xaa,0x01,0x16,0x00,0x5a,0x2d,0x3b,0x27,0x3b,0x83,0x2b,0x45}, 8333}, - {{0x2a,0x00,0x12,0xd8,0x70,0x01,0x00,0x01,0x46,0xe7,0x69,0x15,0x75,0xbe,0x92,0xf9}, 8333}, + {{0x26,0x20,0x00,0x6e,0xa0,0x00,0x20,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06}, 8333}, + {{0x28,0x04,0x01,0x4d,0x4c,0x93,0x98,0x09,0x97,0x69,0xda,0x80,0x18,0x32,0x34,0x80}, 8333}, + {{0x2a,0x00,0x13,0x28,0xe1,0x01,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x63}, 8333}, {{0x2a,0x00,0x13,0x98,0x00,0x04,0x2a,0x03,0x02,0x15,0x5d,0xff,0xfe,0xd6,0x10,0x33}, 8333}, + {{0x2a,0x00,0x13,0xa0,0x30,0x15,0x00,0x01,0x00,0x85,0x00,0x14,0x00,0x79,0x00,0x26}, 8333}, {{0x2a,0x00,0x16,0x30,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01}, 8333}, {{0x2a,0x00,0x17,0x68,0x20,0x01,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x6a}, 8333}, {{0x2a,0x00,0x18,0x28,0xa0,0x04,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x66}, 8333}, - {{0x2a,0x00,0x18,0x38,0x00,0x36,0x01,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0xec,0x73}, 8333}, + {{0x2a,0x00,0x18,0x38,0x00,0x36,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0xcb}, 8333}, {{0x2a,0x00,0x18,0x38,0x00,0x36,0x00,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0xd3,0xc6}, 8333}, - {{0x2a,0x00,0x1f,0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x26}, 8333}, - {{0x2a,0x00,0x23,0xa8,0x41,0xd0,0x58,0x00,0x02,0x0c,0x29,0xff,0xfe,0x0d,0x6a,0x75}, 8333}, - {{0x2a,0x00,0x23,0xc5,0xfd,0x01,0x9f,0x00,0x63,0x17,0x7c,0x02,0x78,0x8f,0x88,0xea}, 8333}, - {{0x2a,0x00,0x60,0x20,0x13,0xc2,0x38,0x00,0xbe,0x6a,0xa1,0xc8,0xc9,0xe7,0x65,0xec}, 8333}, - {{0x2a,0x00,0x63,0xc2,0x00,0x08,0x00,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x00,0x71,0x43,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27}, 8333}, - {{0x2a,0x00,0x7b,0x80,0x04,0x52,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x38}, 8333}, + {{0x2a,0x00,0x1c,0x10,0x00,0x02,0x07,0x09,0x58,0xf7,0xe0,0xff,0xfe,0x24,0xa0,0xba}, 22220}, + {{0x2a,0x00,0x1c,0x10,0x00,0x02,0x07,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x17}, 22220}, + {{0x2a,0x00,0x1f,0x40,0x50,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31}, 8333}, + {{0x2a,0x00,0x60,0x20,0x13,0x95,0x14,0x00,0xba,0xf7,0x2d,0x43,0x60,0xb3,0x19,0x8b}, 8333}, + {{0x2a,0x00,0x7c,0x80,0x00,0x00,0x01,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xaf}, 8333}, {{0x2a,0x00,0x8a,0x60,0xe0,0x12,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21}, 8333}, + {{0x2a,0x00,0xab,0x00,0x06,0x03,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333}, + {{0x2a,0x00,0xbb,0xe0,0x00,0xcc,0x00,0x00,0x62,0xa4,0x4c,0xff,0xfe,0x23,0x75,0x10}, 8333}, {{0x2a,0x00,0x0c,0xa8,0x0a,0x1f,0x30,0x25,0xf9,0x49,0xe4,0x42,0xc9,0x40,0x13,0xe8}, 8333}, - {{0x2a,0x00,0x0d,0x70,0x00,0x00,0x00,0x15,0xf8,0x16,0x3e,0xff,0xfe,0x73,0xd8,0x19}, 8333}, - {{0x2a,0x00,0xd8,0x80,0x00,0x05,0x03,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x78}, 8333}, - {{0x2a,0x01,0x02,0x38,0x42,0x0f,0x92,0x00,0xfa,0x5a,0x1a,0x4b,0x1e,0x6a,0xfa,0xdf}, 8333}, + {{0x2a,0x00,0xd2,0xa0,0x00,0x0a,0x3d,0x00,0x1c,0xdf,0x38,0xbb,0xa7,0xd6,0xc2,0x51}, 8333}, + {{0x2a,0x00,0xd8,0x80,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x0e}, 8333}, + {{0x2a,0x00,0x0e,0xc0,0x72,0x07,0x91,0x00,0x5f,0x8f,0x25,0xdd,0x25,0x74,0x39,0x82}, 8333}, + {{0x2a,0x00,0xf8,0x20,0x04,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36}, 8333}, + {{0x2a,0x01,0x01,0x38,0xa0,0x17,0xb0,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42}, 8333}, {{0x2a,0x01,0x04,0x30,0x00,0x17,0x00,0x01,0x00,0x00,0x00,0x00,0xff,0xff,0x11,0x53}, 8333}, - {{0x2a,0x01,0x04,0x88,0x00,0x66,0x10,0x00,0x53,0xa9,0x15,0x73,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0x04,0xf8,0x01,0x20,0x80,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8433}, - {{0x2a,0x01,0x05,0xf0,0xbe,0xef,0x00,0x05,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01}, 52101}, - {{0x2a,0x01,0x07,0x9c,0xce,0xbc,0xa6,0x30,0x9d,0xd8,0xef,0x55,0x83,0x74,0x92,0xa1}, 8333}, - {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11}, 8333}, + {{0x2a,0x01,0x04,0x90,0x00,0x16,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, + {{0x2a,0x01,0x4b,0x00,0x80,0x7c,0x1b,0x00,0xcd,0xa1,0x0c,0x6a,0x2b,0xad,0x24,0x18}, 8333}, + {{0x2a,0x01,0x4b,0x00,0x80,0xe7,0x54,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, + {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x42,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8433}, {{0x2a,0x01,0x07,0xa0,0x00,0x02,0x13,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333}, - {{0x2a,0x01,0x07,0xc8,0xaa,0xb6,0x00,0xdb,0x50,0x54,0x00,0xff,0xfe,0xca,0xcf,0xc8}, 8333}, - {{0x2a,0x01,0x8b,0x81,0x64,0x03,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x01,0xcb,0x00,0x07,0xcd,0xb0,0x00,0xfa,0x1f,0x0b,0xd1,0x0f,0xe0,0x62,0xa6}, 8333}, - {{0x2a,0x01,0xcb,0x00,0x0d,0x3d,0x77,0x00,0x02,0x27,0x0e,0xff,0xfe,0x28,0xc5,0x65}, 8333}, + {{0x2a,0x01,0x07,0xa7,0x00,0x02,0x14,0x67,0x0e,0xc4,0x7a,0xff,0xfe,0xe2,0x56,0x90}, 8333}, + {{0x2a,0x01,0x07,0xc8,0xd0,0x02,0x01,0x0f,0x50,0x54,0x00,0xff,0xfe,0x5c,0xda,0xc7}, 8333}, + {{0x2a,0x01,0x07,0xc8,0xd0,0x02,0x03,0x18,0x50,0x54,0x00,0xff,0xfe,0xbe,0xcb,0xb1}, 8333}, + {{0x2a,0x01,0x87,0x40,0x00,0x01,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x8c,0x6a}, 8333}, + {{0x2a,0x01,0xcb,0x00,0x0f,0x98,0xca,0x00,0x50,0x54,0x00,0xff,0xfe,0xd4,0x76,0x3d}, 8333}, + {{0x2a,0x01,0xcb,0x14,0x0c,0xf6,0xbc,0x00,0x21,0xe5,0xf1,0x2e,0x32,0xc8,0x01,0x45}, 8333}, + {{0x2a,0x01,0x00,0xd0,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x45}, 8333}, {{0x2a,0x01,0x00,0xd0,0xbe,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12}, 8333}, - {{0x2a,0x01,0x00,0xd0,0xf3,0x4f,0x00,0x01,0x1f,0x67,0xe2,0x50,0x6a,0xeb,0xb9,0xc4}, 8333}, - {{0x2a,0x01,0x0e,0x34,0xee,0x6b,0x2a,0xb0,0x88,0xc2,0x1c,0x12,0xf4,0xeb,0xc2,0x6c}, 8333}, - {{0x2a,0x01,0x0e,0x35,0x2f,0xba,0x2e,0x90,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x01}, 8333}, - {{0x2a,0x02,0x12,0x05,0x50,0x5d,0xeb,0x50,0xbe,0xae,0xc5,0xff,0xfe,0x42,0xa9,0x73}, 8333}, - {{0x2a,0x02,0x12,0x0b,0x2c,0x3f,0x0a,0x90,0x10,0xdd,0x31,0xff,0xfe,0x42,0x50,0x79}, 8333}, - {{0x2a,0x02,0x01,0x30,0x03,0x00,0x15,0x20,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x02,0x13,0xb8,0x40,0x00,0x10,0x00,0x02,0x16,0xe6,0xff,0xfe,0x92,0x86,0x19}, 8333}, + {{0x2a,0x01,0x0e,0x35,0x2e,0x40,0x68,0x30,0x02,0x11,0x32,0xff,0xfe,0xa6,0xde,0x3d}, 8333}, + {{0x2a,0x02,0x12,0x05,0xc6,0xaa,0x60,0xc0,0x70,0xd8,0xaa,0xee,0xa8,0x2d,0x99,0x3c}, 8333}, + {{0x2a,0x02,0x01,0x69,0x05,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x14}, 8333}, {{0x2a,0x02,0x01,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x5b,0x8f,0x53,0x8c}, 8333}, - {{0x2a,0x02,0x21,0x68,0x80,0x62,0xdb,0x00,0x96,0xde,0x80,0xff,0xfe,0xa3,0xfd,0x00}, 8333}, - {{0x2a,0x02,0x27,0x70,0x00,0x05,0x00,0x00,0x02,0x1a,0x4a,0xff,0xfe,0x44,0x83,0x70}, 8333}, - {{0x2a,0x02,0x27,0x88,0x08,0x64,0x0f,0xb3,0x5b,0x8a,0xc8,0xf7,0x9f,0xff,0xae,0x2d}, 8333}, - {{0x2a,0x02,0x2f,0x0d,0x06,0x07,0xbc,0x00,0x5e,0x9a,0xd8,0xff,0xfe,0x57,0x8b,0xc5}, 8333}, - {{0x2a,0x02,0x03,0x48,0x00,0x9a,0x83,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, + {{0x2a,0x02,0x03,0x48,0x00,0x62,0x5e,0xf7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, {{0x2a,0x02,0x03,0x90,0x90,0x00,0x00,0x00,0x02,0x18,0x7d,0xff,0xfe,0x10,0xbe,0x33}, 8333}, - {{0x2a,0x02,0x47,0x80,0x00,0x08,0x00,0x06,0x00,0x02,0x35,0x4e,0x12,0x56,0x7a,0x04}, 8333}, - {{0x2a,0x02,0x05,0x78,0x4f,0x07,0x00,0x24,0x76,0xad,0xce,0xf7,0x93,0xc1,0xb9,0xb9}, 8333}, - {{0x2a,0x02,0x6d,0x40,0x30,0xf6,0xe9,0x01,0x89,0xb8,0xbb,0x58,0x02,0x5a,0x60,0x50}, 8333}, - {{0x2a,0x02,0x07,0x50,0x00,0x07,0x0c,0x11,0x50,0x54,0x00,0xff,0xfe,0x43,0xeb,0x81}, 8333}, {{0x2a,0x02,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0xdc,0x8d,0xe0}, 8333}, - {{0x2a,0x02,0x7b,0x40,0x4f,0x62,0x19,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0x81,0x08,0x95,0xbf,0xea,0xe3,0x02,0x11,0x32,0xff,0xfe,0x8e,0xb5,0xb8}, 8333}, - {{0x2a,0x02,0x0e,0x00,0xff,0xf0,0x02,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x02,0x0e,0x00,0xff,0xf0,0x02,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a}, 8333}, - {{0x2a,0x03,0x1b,0x20,0x00,0x01,0xf4,0x10,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x3e}, 16463}, + {{0x2a,0x02,0x7b,0x40,0xb0,0xdf,0x89,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, + {{0x2a,0x02,0x7b,0x40,0xb9,0x05,0x37,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, + {{0x2a,0x02,0x81,0x0d,0x8c,0xbf,0xf3,0xa8,0x96,0xc6,0x91,0xff,0xfe,0x17,0xae,0x1d}, 8333}, + {{0x2a,0x02,0x83,0x89,0x01,0xc0,0x96,0x80,0x02,0x01,0x2e,0xff,0xfe,0x82,0xb3,0xcc}, 8333}, + {{0x2a,0x02,0xa4,0x54,0xa5,0x16,0x00,0x01,0x05,0x17,0x09,0x28,0x7e,0x0d,0x95,0x7c}, 8333}, + {{0x2a,0x02,0x0a,0xf8,0xfa,0xb0,0x08,0x04,0x01,0x51,0x02,0x36,0x00,0x34,0x01,0x61}, 8333}, + {{0x2a,0x02,0x0a,0xf8,0xfa,0xb0,0x08,0x08,0x00,0x85,0x02,0x34,0x01,0x45,0x01,0x32}, 8333}, + {{0x2a,0x02,0x0e,0x00,0xff,0xf0,0x01,0xe2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a}, 8333}, + {{0x2a,0x03,0x22,0x60,0x30,0x06,0x00,0x0d,0xd3,0x07,0x5d,0x1d,0x32,0xca,0x1f,0xe8}, 8333}, {{0x2a,0x03,0x60,0x00,0x08,0x70,0x00,0x00,0x00,0x46,0x00,0x23,0x00,0x87,0x02,0x18}, 8333}, {{0x2a,0x03,0x9d,0xa0,0x00,0xf6,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, + {{0x2a,0x03,0xc9,0x80,0x00,0xdb,0x00,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333}, {{0x2a,0x03,0xe2,0xc0,0x01,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x04,0x21,0x80,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf2}, 8333}, - {{0x2a,0x04,0x21,0x80,0x00,0x01,0x00,0x0c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x15}, 8333}, - {{0x2a,0x04,0x52,0xc0,0x01,0x01,0x09,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0xdc,0xbe}, 8333}, + {{0x2a,0x04,0x35,0x44,0x10,0x00,0x15,0x10,0x70,0x6c,0xab,0xff,0xfe,0x6c,0x50,0x1c}, 8333}, + {{0x2a,0x04,0x52,0xc0,0x01,0x01,0x03,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0x87}, 8333}, + {{0x2a,0x04,0x52,0xc0,0x01,0x01,0x03,0xfb,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0x27}, 8333}, {{0x2a,0x04,0xee,0x41,0x00,0x83,0x50,0xdf,0xd9,0x08,0xf7,0x1d,0x2a,0x86,0xb3,0x37}, 8333}, - {{0x2a,0x05,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00}, 8333}, - {{0x2a,0x05,0xfc,0x87,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, - {{0x2a,0x05,0xfc,0x87,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333}, - {{0x2a,0x07,0x57,0x41,0x00,0x00,0x06,0x9d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x07,0x57,0x41,0x00,0x00,0x07,0xcd,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0x2a,0x07,0x72,0x00,0xff,0xff,0xc5,0x3f,0x00,0x00,0x00,0x00,0x00,0xe1,0x00,0x17}, 8333}, + {{0x2a,0x05,0x6d,0x40,0xb9,0x4e,0xd1,0x00,0x02,0x25,0x90,0xff,0xfe,0x0d,0xcf,0xc2}, 8333}, + {{0x2a,0x05,0xe5,0xc0,0x00,0x00,0x01,0x00,0x02,0x50,0x56,0xff,0xfe,0xb9,0xd6,0xcb}, 8333}, + {{0x2a,0x05,0xfc,0x87,0x00,0x01,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333}, + {{0x2a,0x05,0xfc,0x87,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333}, + {{0x2a,0x07,0x57,0x41,0x00,0x00,0x11,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, + {{0x2a,0x07,0xa8,0x80,0x46,0x01,0x10,0x62,0xb4,0xb4,0xbd,0x2a,0x39,0xd4,0x7a,0xcf}, 51401}, + {{0x2a,0x07,0xab,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x09,0x46}, 8333}, {{0x2a,0x07,0xb4,0x00,0x00,0x01,0x03,0x4c,0x00,0x00,0x00,0x00,0x00,0x02,0x10,0x02}, 8333}, + {{0x2a,0x0a,0x8c,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb4}, 8333}, + {{0x2a,0x0a,0xc8,0x01,0x00,0x01,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x83}, 8333}, {{0x2a,0x0b,0xae,0x40,0x00,0x03,0x4a,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15}, 8333}, - {{0x2a,0x0e,0xb7,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xd1,0xf0,0x5b}, 8333}, + {{0x2a,0x0f,0xdf,0x00,0x00,0x00,0x02,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46}, 8333}, + {{0x2c,0x0f,0xf5,0x98,0x00,0x05,0x00,0x01,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, {{0x2c,0x0f,0xfc,0xe8,0x00,0x00,0x04,0x00,0x0b,0x7c,0x00,0x00,0x00,0x00,0x00,0x01}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd1,0x18,0xf0,0x4c,0x65,0x20,0x3d,0x5b,0x12,0x64}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdf,0x01,0x01,0x59,0xad,0xa2,0x20,0x7d,0x6f,0x85}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd9,0xaf,0x04,0x04,0x09,0x8c,0xf1,0x2c,0x3f,0xae}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdc,0x80,0xc4,0x72,0x66,0xe6,0x0e,0x29,0xa7,0x02}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdd,0xbf,0xf3,0xc5,0x0b,0x37,0xa1,0xee,0x39,0xeb}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe7,0xae,0x7d,0x48,0x29,0x92,0x51,0x85,0xf0,0xb4}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe1,0x09,0xce,0x42,0x40,0x64,0x52,0xfc,0x59,0x34}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe1,0xc0,0xf5,0xc6,0x6a,0x7c,0x53,0x03,0xb3,0x49}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe5,0x37,0x8d,0xe4,0xba,0x23,0x30,0xd9,0xfa,0x88}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xef,0xc7,0x89,0xa3,0x21,0x02,0x3e,0xee,0x2a,0x1f}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe9,0xa8,0x02,0x51,0x62,0xfd,0xd9,0xc3,0x69,0x8c}, 8334}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0x27,0x51,0xf0,0x6a,0xf6,0x84,0x21,0xab,0x95}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0xd8,0x9c,0xf9,0x8c,0x42,0xb0,0x00,0x82,0xdd}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf1,0x29,0x11,0x5d,0xd0,0x90,0x39,0x07,0xa2,0x10}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf2,0x2b,0x55,0x12,0x44,0x72,0x64,0xc7,0x87,0x1c}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf4,0xd6,0x70,0x79,0xa9,0x98,0xa9,0x67,0x94,0x1b}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf6,0x18,0x60,0xd5,0xad,0xf0,0xfa,0xd2,0xb2,0xbc}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfe,0xb1,0xa6,0xf6,0x20,0x8e,0x38,0xcc,0x59,0x59}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf8,0x7f,0xda,0x07,0xa3,0x03,0xde,0x72,0x31,0x13}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfd,0xc1,0x07,0xc7,0xe4,0xbc,0x66,0xb6,0xa4,0x21}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x07,0xb8,0x70,0x22,0x12,0x5f,0xfc,0xbd,0x74,0xd5}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x00,0x7e,0x59,0x8c,0xb6,0xf4,0x0e,0x3b,0xee,0x24}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0x28,0xf3,0x06,0x63,0x83,0xd9,0x62,0xbe,0x99}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0x88,0x6e,0xfa,0x39,0x51,0xbf,0x19,0x63,0x06}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0x90,0xd0,0xbb,0xf3,0x59,0x0d,0x26,0xca,0xed}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x03,0x48,0xce,0x82,0x1c,0x14,0x75,0x95,0xfe,0x79}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x04,0xf7,0x6e,0xc1,0x12,0x16,0x4c,0x6a,0x21,0x24}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x05,0x1d,0xcc,0xa6,0x4f,0xe7,0x2b,0x81,0xd7,0xc2}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0b,0xac,0x6e,0x3e,0x25,0xf6,0xcc,0x8a,0x90,0x1c}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x12,0x68,0x45,0x6b,0x4f,0xe5,0x6b,0xc3,0xe4,0x34}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x12,0x96,0x00,0x6a,0xe3,0x05,0xa2,0x1f,0xf4,0xa6}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x13,0xae,0x88,0xd3,0xfe,0x6b,0x4b,0x6d,0xd4,0x69}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x15,0xa1,0xa2,0xd0,0x5d,0xe3,0x16,0xfd,0xb9,0x22}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x19,0x80,0xd8,0xfc,0x65,0x2c,0x80,0x20,0x61,0x8b}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1a,0x43,0x29,0x3d,0x95,0x58,0xbc,0x84,0xa1,0x12}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1b,0x0b,0x67,0x57,0xb8,0x13,0x5f,0x5a,0x2d,0x09}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1b,0xf4,0x45,0x14,0x37,0xa0,0x5e,0x32,0xc6,0x7c}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0xb5,0x42,0x87,0x01,0x89,0xa7,0x99,0x4a,0x72}, 4333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x20,0xd4,0xc2,0x90,0x00,0x7d,0x41,0x53,0xcd,0x54}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x22,0x46,0xe2,0x63,0x74,0x06,0x36,0x2c,0xfc,0x32}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x22,0xc0,0x35,0xd6,0xc5,0x58,0x00,0x7b,0xb9,0x91}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x29,0x4f,0x7f,0x4e,0x70,0xf9,0x12,0x17,0x0e,0x80}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0x5a,0xdc,0xcc,0x8e,0x6f,0xfb,0x46,0xfb,0xb8}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0xb1,0x73,0xba,0xcd,0xb8,0xeb,0xfc,0x60,0x36}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0xca,0x2b,0xad,0x7a,0x9c,0x25,0xa5,0xf1,0x22}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0xd6,0x3d,0x06,0xf8,0xae,0x71,0xce,0x8e,0x5c}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3a,0xda,0xd3,0xb7,0x57,0x4e,0xa0,0x52,0xc1,0x32}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3b,0x61,0x66,0x41,0x0a,0x2b,0x1a,0xa7,0x8d,0x20}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3d,0x58,0x97,0x54,0x60,0x93,0x90,0xde,0x6e,0xcd}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3d,0xb2,0x20,0xb4,0x8d,0x7f,0x87,0x27,0xf9,0xd6}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x47,0x48,0xb5,0xdb,0x2d,0x1a,0x68,0xa2,0x6b,0x9a}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x40,0x1f,0x57,0xdb,0x32,0xe1,0x9e,0x15,0xf8,0xaa}, 8885}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x41,0x7e,0x59,0x54,0xd8,0x85,0x9d,0x6b,0xa8,0x4d}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x42,0xe8,0xac,0xa4,0x19,0xba,0xef,0x10,0xd2,0xd8}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x54,0xac,0x5c,0x52,0x2d,0x32,0xd9,0xee,0xd3,0xe1}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0xe9,0xa3,0x85,0x0e,0x8a,0xaa,0x3c,0x31,0x20}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5d,0x6a,0x62,0x0d,0xef,0x63,0xd0,0x6a,0x0c,0xf9}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x62,0xb6,0x16,0x91,0xfd,0xa0,0x5d,0x4f,0xa3,0x9c}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x65,0x0e,0xfe,0x6b,0x13,0x0d,0x91,0xe8,0x17,0xda}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0x54,0x79,0x04,0x7e,0xb1,0xed,0xf7,0x39,0x0f}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x68,0xd8,0x18,0xa4,0x55,0xa6,0xa5,0xe4,0x89,0xcc}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x69,0x78,0x8c,0x3d,0xb8,0x4d,0x8a,0xf1,0x25,0x9f}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x87,0x6f,0x62,0xd9,0x9e,0xc7,0x0b,0x5e,0x85}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x77,0x24,0xbe,0xb4,0x1e,0x49,0x20,0x64,0x6d,0x7e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x73,0xc8,0xd1,0x50,0x24,0x0c,0x21,0x7d,0x86,0x89}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x75,0x42,0xaa,0x98,0x6b,0x5a,0xb7,0x7b,0x90,0x07}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x79,0xb4,0x92,0x1f,0xda,0x2a,0xa1,0xb0,0xe1,0xf2}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7a,0x84,0x6b,0x97,0x5b,0xb4,0xb6,0xbb,0x42,0xb0}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x80,0xe6,0x0a,0x7f,0x48,0x2d,0x81,0x47,0x4f,0xc1}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x82,0x06,0xd8,0xc3,0x1a,0x76,0x73,0xb6,0xe6,0x10}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x89,0x00,0x3c,0x05,0x13,0xed,0x49,0x81,0x1c,0x9e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x96,0x88,0xfb,0x80,0x5f,0x75,0x71,0xbf,0x46,0x89}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x90,0x26,0xe2,0xde,0x42,0xdd,0xd2,0x01,0xde,0x4c}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x95,0x7a,0xe4,0x4c,0xad,0x93,0x0a,0xe1,0x6e,0xd4}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa1,0x66,0x1b,0x73,0x28,0xed,0x97,0x91,0x58,0xee}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa6,0x76,0xfa,0x8c,0xe8,0x26,0xf7,0xfd,0x56,0xf6}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xae,0xaf,0xf3,0x3d,0x3b,0x91,0xee,0x56,0xaf,0x5d}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xab,0xab,0xcf,0x1e,0x73,0xf1,0xb0,0x8b,0x8d,0x81}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0xb6,0x1d,0xc2,0xe2,0xb0,0xa3,0x10,0x43,0x4e}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0x88,0x41,0x25,0x9c,0xb7,0x14,0xef,0x78,0xbf}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb3,0x2e,0x2f,0x02,0x4a,0xe0,0x3b,0x7c,0x02,0xe7}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb4,0x22,0x02,0xb7,0x99,0x02,0xf6,0x10,0x84,0xf1}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb9,0xd1,0xdb,0xf6,0x02,0xe7,0x08,0xbc,0x0d,0x5c}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xba,0xbc,0x14,0xad,0x86,0xad,0x9c,0x9a,0xbb,0x29}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbb,0x0d,0x1f,0x96,0x4c,0x7f,0xc2,0x60,0xd2,0x2a}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbb,0x85,0x5c,0xec,0x79,0xc5,0x34,0xac,0xd3,0xc5}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbd,0x7e,0xf9,0xf8,0x93,0xb5,0xd1,0x83,0x4a,0x5e}, 8444}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc5,0x19,0x7f,0x82,0x49,0xf9,0x48,0xe7,0x65,0x02}, 8333}, - {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcb,0x00,0x31,0xca,0x04,0x5d,0xb4,0xec,0x58,0xa1}, 8444} + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd6,0xbc,0x4a,0x3c,0x6d,0x03,0xa9,0x4e,0x1f,0x55}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd6,0x8f,0xf0,0xf8,0xbb,0x10,0x00,0x18,0x42,0x54}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd6,0xec,0x32,0xc1,0x59,0x9c,0xd8,0x46,0xd5,0x48}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd6,0xf0,0x8d,0x96,0x37,0xc3,0x27,0x61,0x9a,0x24}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd0,0x12,0xe6,0xed,0x8e,0xc1,0x78,0x8d,0x1c,0x21}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd0,0x4a,0xc5,0xbd,0x5d,0xe9,0xca,0x57,0xaf,0xc4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd0,0x94,0xc0,0x97,0xd2,0x32,0xed,0x81,0x92,0x67}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd1,0xd5,0x49,0x23,0xa6,0x10,0x01,0x49,0xda,0x05}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd2,0x2a,0x76,0x2c,0x37,0x09,0x9a,0xa1,0x61,0x4b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd3,0x19,0x77,0x50,0xf5,0xf3,0x48,0x17,0x59,0x50}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd4,0x24,0xda,0xf8,0x97,0x6d,0x28,0x80,0x47,0xf9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd4,0x28,0x30,0x9d,0x6d,0xac,0x1e,0xb4,0x6e,0x59}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd5,0x13,0x71,0x95,0xd5,0x2e,0x12,0xf6,0x0e,0x6e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd5,0xc6,0x62,0x50,0xb1,0x22,0xb6,0x4a,0x31,0x56}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd5,0xc7,0x99,0x46,0x87,0x91,0x13,0xc9,0xc9,0x16}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdf,0x22,0x06,0xea,0xce,0x87,0x08,0x09,0x32,0x52}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdf,0xa1,0xf5,0x1c,0xe4,0x4e,0x97,0x71,0xee,0xc5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdf,0xf7,0x64,0x8e,0x4f,0xa3,0xbb,0xaa,0x4f,0x30}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdf,0xfc,0xa5,0x92,0x7d,0xbc,0x03,0x13,0x69,0x35}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdf,0xd5,0x61,0xfc,0xb7,0x73,0xff,0xef,0x2f,0xaa}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd9,0x3b,0x3f,0x9e,0x1c,0x02,0xe7,0xd9,0xba,0xb7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd9,0x83,0x73,0x90,0x25,0x3b,0xa9,0x4b,0x18,0x5b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd9,0xcc,0x14,0xe4,0x9a,0x68,0x6d,0x8a,0x12,0xc5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xda,0x29,0x4a,0xc4,0x7a,0xb0,0x0e,0x0d,0x0a,0xee}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xda,0x67,0x7a,0x24,0x60,0x45,0x8f,0xe4,0x2e,0x74}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xda,0xfa,0x48,0x68,0x74,0xfb,0x2b,0x21,0x27,0x80}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdb,0x5c,0x56,0x99,0xb0,0x5c,0x08,0x43,0xb7,0xee}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdc,0x79,0xc1,0x8f,0x29,0x44,0xf2,0xdc,0x00,0xf6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xdd,0x66,0x1a,0x59,0x93,0x73,0x7f,0x58,0x76,0x19}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe7,0x9c,0x7c,0xce,0x79,0xe3,0xc8,0xa4,0x73,0x66}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe7,0xca,0xbd,0xa2,0xab,0xe5,0x7b,0xe4,0xca,0x71}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe7,0xd1,0xe8,0x45,0x7a,0x42,0x60,0x2b,0x2c,0xde}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe7,0xe9,0x47,0x9b,0x22,0x6c,0x6c,0x03,0xba,0x6e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe0,0xba,0x25,0x23,0x7f,0x25,0x5c,0x51,0xcb,0xc3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe1,0x21,0xbf,0x26,0x37,0xfd,0xe9,0x89,0x95,0xe2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe1,0x2c,0xa1,0xde,0xa2,0x37,0x7e,0x01,0xc5,0xa8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe1,0x57,0x53,0x20,0x2d,0x66,0x9a,0xb1,0xed,0xa0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe2,0x00,0xe6,0xcf,0x0c,0xe7,0xd0,0xc0,0x58,0x9c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe2,0x6f,0x9d,0xfd,0xce,0xa7,0x40,0x6f,0xfb,0x62}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe3,0x1a,0xaa,0xa7,0xc7,0x07,0xf6,0x48,0x34,0x2a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe3,0x5b,0x4c,0x5d,0x9d,0x57,0x66,0xbc,0x26,0x1b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe3,0x73,0xac,0x1b,0x82,0x6b,0xa6,0x4d,0x91,0x3f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe3,0xdd,0x9b,0x1f,0xdd,0xf7,0x30,0x6c,0x8c,0x6a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe4,0x0c,0x50,0xf7,0xd1,0xab,0xc2,0xc2,0x4a,0xff}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe4,0x64,0x0b,0xeb,0x73,0x04,0x33,0x66,0x21,0x89}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe5,0x3a,0x9e,0x83,0x1e,0x88,0x24,0xeb,0x4f,0x8c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe5,0x5d,0x1a,0xcd,0xd8,0x21,0x8f,0xcc,0x86,0xb1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xee,0xa5,0xc4,0xf5,0xeb,0x1d,0x96,0xfc,0x9e,0x76}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe8,0x02,0xf4,0x22,0x05,0xa9,0x14,0xe2,0x26,0x2e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe8,0x30,0x3c,0xde,0xfe,0x4e,0x1d,0x9d,0xb4,0x99}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe8,0xaf,0x91,0xca,0x33,0x72,0xba,0x33,0x3b,0x80}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe9,0x07,0x44,0x29,0xf4,0x1a,0x09,0xb4,0xe2,0x25}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe9,0x1e,0x40,0x15,0x4c,0xc0,0x38,0x5a,0xf4,0x7d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe9,0x71,0x75,0xe6,0x68,0x16,0xe7,0xe6,0xba,0x79}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe9,0xc7,0xe2,0x60,0x96,0xee,0x02,0xd8,0x78,0xc1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xea,0x70,0x5c,0x9e,0xca,0x90,0x7d,0x48,0xc5,0xfa}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0x5c,0xe8,0x18,0x53,0xef,0xbe,0x83,0x77,0xf5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0x64,0x56,0x71,0xb0,0x86,0x72,0xf8,0xa6,0x2f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0xa1,0x29,0xde,0x4f,0xc9,0xd6,0x64,0x90,0xbe}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xeb,0xf3,0x96,0x0f,0x93,0x2b,0x9b,0x18,0x64,0x3a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xec,0x84,0xa6,0x5f,0x98,0xa0,0x82,0xd7,0xf1,0x0e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xed,0x09,0xfb,0x3a,0x39,0x0b,0x7c,0x77,0x37,0x64}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xed,0xae,0x7b,0xea,0x6e,0xcb,0xdd,0x52,0xfb,0x3b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xed,0xd5,0xbc,0x51,0xbb,0xf1,0x37,0xa2,0x6f,0x88}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xee,0x4c,0x79,0xe8,0xdf,0xa8,0xa4,0x07,0xa3,0xdd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf6,0x86,0x21,0xbe,0xa3,0x72,0xcb,0x95,0x0f,0x2b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf6,0xc2,0xa7,0x69,0x87,0x45,0xda,0xdd,0x07,0xe3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf7,0xce,0x9a,0x96,0xbe,0xb2,0x05,0x30,0x2d,0x9d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf1,0xbc,0xa7,0x71,0x4b,0x51,0x7a,0x09,0xac,0x68}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf2,0xbb,0x98,0x90,0x97,0xb7,0x04,0x01,0xdd,0x1d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf2,0x8b,0xd0,0x60,0xeb,0x79,0x1b,0x8b,0x18,0x12}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf3,0x00,0x83,0x5d,0x35,0x11,0x27,0xc7,0xa2,0x64}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf4,0x49,0x29,0x57,0x83,0xab,0xd6,0x1e,0xa0,0xe7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf4,0x52,0x4b,0xf8,0xd8,0xa0,0x28,0x8d,0x8b,0xa4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf4,0x94,0x66,0x97,0x9b,0x7b,0xce,0x3a,0xa6,0x80}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf4,0xa7,0x70,0x38,0x74,0xb2,0x24,0x6e,0xca,0x07}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf5,0xe1,0x8e,0x4e,0x5e,0x0b,0xbd,0x4e,0x8c,0xcc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf8,0x2a,0xd5,0xec,0x70,0x79,0xa9,0xad,0xa6,0xa0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf9,0x4b,0xcb,0x2b,0x5e,0xf3,0x5d,0xad,0xce,0xed}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf9,0xd0,0xf0,0xd3,0x25,0x18,0xb1,0x98,0x29,0x46}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfc,0x92,0xc5,0xe6,0x33,0x3a,0x56,0xf2,0xe0,0x6a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfc,0xe9,0x3d,0xe6,0x7a,0x02,0xad,0x16,0x5b,0xd7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfd,0x0f,0x24,0xe5,0x3e,0x6d,0xf6,0x32,0xb6,0xf3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfd,0x99,0xcb,0x49,0xdb,0xb5,0x41,0x3b,0xb4,0x33}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xfe,0x14,0xcc,0xd3,0x01,0xb0,0xf4,0xf9,0xe4,0xdc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x06,0xbe,0x1a,0x9d,0x0d,0x07,0x31,0xad,0xa6,0xee}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x07,0x77,0x59,0x8d,0x9f,0xa2,0x09,0x3e,0xd4,0x6b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x07,0x7d,0xdf,0xea,0xe9,0xa3,0x8a,0xd9,0xe8,0x6f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x00,0x5f,0xae,0xa9,0xa8,0x28,0xe4,0xd1,0x6a,0x35}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x01,0x0b,0x7f,0xd0,0x39,0x78,0x17,0xf1,0x2c,0x0a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0x3b,0x1d,0x0d,0x0e,0xcb,0x89,0xf8,0xc4,0x79}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0x1f,0x47,0xbc,0xe8,0x9e,0xc8,0xd3,0x19,0xe9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0xcc,0xf4,0xa7,0x06,0x1e,0xcd,0x36,0xb1,0xef}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x02,0xd0,0x7a,0x03,0xf1,0x3e,0x05,0xce,0xe8,0xf1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x03,0x36,0x6c,0x60,0xb8,0x6d,0xf3,0x6c,0x5c,0xf7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x03,0x54,0xec,0xe4,0xa7,0x5e,0xa3,0xba,0x0b,0xd4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x04,0xf7,0x3b,0x25,0x61,0x98,0xb4,0xb8,0x36,0x1d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x05,0x60,0xe0,0xaf,0xfa,0x7b,0x05,0xee,0x0f,0x08}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x05,0x98,0x3c,0xe8,0xb2,0xd8,0x7a,0x7e,0xd2,0x7d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x06,0x31,0x67,0xa3,0x1f,0xf8,0x69,0x31,0xa6,0x29}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0e,0x91,0xb7,0xa7,0xe2,0xd7,0x05,0x57,0xc6,0x5f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0f,0x10,0xb2,0x07,0x17,0x15,0x3c,0xd9,0xcd,0x0e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0f,0x2b,0x55,0x06,0x08,0x78,0x98,0xab,0x3f,0x95}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x08,0xc6,0x58,0x5d,0xf2,0xea,0x02,0x3d,0x96,0x76}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x09,0x3a,0x13,0x09,0xee,0xe3,0x9d,0x4b,0xf6,0x18}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x09,0x96,0x0e,0x33,0xd9,0x24,0xeb,0x3a,0xfd,0x72}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x09,0xf7,0xa3,0x66,0xdb,0x6e,0x04,0xac,0xc2,0x93}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x09,0xdd,0xc5,0x38,0x6f,0x21,0xdb,0xfb,0xc7,0x77}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0x26,0x27,0x21,0xbc,0x8a,0xca,0x0e,0x5a,0x17}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0x2d,0xf9,0x79,0x25,0xf4,0x74,0xc2,0xec,0x54}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0xbf,0x87,0xf8,0x8f,0x6b,0x04,0xb5,0xc3,0xfa}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0xc4,0xa9,0xc4,0xd5,0x27,0x6a,0x49,0xa6,0x4a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0xec,0x17,0xfc,0xc5,0x19,0x4a,0x39,0x5f,0x86}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0b,0x6e,0xdf,0x42,0x02,0xef,0x4d,0x56,0xf5,0xcf}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0b,0xfe,0xed,0x69,0x75,0x12,0x41,0x62,0x2e,0xb5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0c,0x21,0x88,0x50,0x46,0x4f,0x26,0x23,0xb7,0xdc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0d,0x47,0x96,0x52,0x62,0x81,0x7e,0x6c,0xe5,0xbd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x16,0xfd,0x96,0x10,0xc9,0x52,0x1a,0x59,0xb2,0x65}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x17,0x0a,0xdf,0x68,0xcd,0x5c,0xd6,0x68,0xbe,0x75}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x10,0x00,0x45,0xf7,0x04,0x1d,0x50,0xe7,0x43,0x2a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x10,0x21,0xde,0x00,0x2b,0x28,0x62,0xda,0x30,0x63}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x11,0x22,0xd8,0xb2,0x2a,0xee,0x5c,0xcc,0xbb,0x2d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x11,0xe2,0x8f,0x22,0x66,0x48,0x00,0x67,0x17,0x93}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x13,0x45,0x64,0x2b,0x73,0x68,0xf4,0x44,0xb3,0xb9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x15,0x30,0x98,0x3b,0x28,0x23,0x04,0xcb,0x02,0xeb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x15,0xff,0x00,0x68,0xcf,0x86,0x1f,0xf7,0xac,0x7d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x16,0x5f,0xfb,0x18,0x14,0x97,0x0d,0x54,0x3b,0xfa}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1e,0x8a,0xde,0xf2,0x25,0xc2,0x46,0x06,0x99,0x1c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1e,0xa4,0xae,0x76,0x9e,0x10,0x3d,0xcc,0x12,0x07}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1e,0xc0,0xeb,0x31,0xa6,0xaa,0xa7,0x2c,0xa0,0x04}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1f,0x51,0x4e,0x01,0x19,0xde,0x34,0xa3,0x08,0xc9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1f,0xb2,0x1b,0x6a,0x57,0x6d,0xcc,0x9e,0xca,0xbb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x18,0x7b,0x11,0xf4,0x9c,0xf4,0xfe,0xc3,0x21,0xa8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x18,0x91,0xa3,0x51,0x6e,0x8a,0xf9,0xcc,0x27,0xbd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x18,0xdf,0x33,0xe9,0x96,0x9e,0xe3,0x2a,0xb9,0xc6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x19,0x63,0x6c,0x83,0xe5,0x11,0x04,0xa6,0xb5,0x92}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1a,0x6c,0x74,0x95,0x3c,0x89,0xf6,0xec,0xef,0x09}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1a,0x95,0xd6,0x31,0xe4,0xea,0x66,0x97,0x0d,0x5d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1b,0x93,0xbc,0x99,0x92,0x0e,0x69,0x16,0x40,0xcf}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1b,0xc4,0x4e,0x17,0x71,0x14,0x06,0x3c,0x86,0xfd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x6c,0xed,0xd5,0xb7,0x11,0xfa,0xec,0x94,0x2e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0x10,0xa5,0x20,0x77,0x43,0xf6,0xbc,0x12,0xed}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0x20,0x35,0xa1,0xf3,0x16,0xb4,0x8f,0x1c,0xbd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0x30,0xfe,0x09,0xc7,0xe8,0xfe,0xd3,0xee,0x83}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0x33,0xd9,0xd9,0xdb,0xcf,0xc5,0xde,0xae,0xe9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1d,0x69,0xe1,0xac,0x11,0xf1,0x32,0x2f,0x5c,0x8d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1e,0x3d,0x98,0x4b,0x9e,0xc0,0x96,0x40,0x63,0x0f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1e,0x75,0x81,0xb1,0x3b,0xc4,0x22,0x26,0x72,0x3f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x26,0x83,0xa0,0x76,0x54,0xa8,0xc1,0x6c,0xde,0x83}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x26,0xf6,0x7e,0xfd,0x3a,0x25,0x94,0xa8,0x49,0xbd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x27,0x54,0x94,0x03,0x1f,0x7e,0x53,0xd8,0x3f,0x35}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x27,0xd0,0xa7,0x73,0x43,0xd5,0xb2,0x26,0x57,0x1c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x20,0x3c,0x17,0x1f,0x8a,0x74,0xe1,0xdf,0x5a,0x5d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x21,0x47,0x7f,0x18,0x5c,0x97,0x49,0x9c,0x40,0x86}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x21,0x62,0xfa,0x51,0x02,0xf5,0x14,0x4c,0x40,0x52}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x21,0xa3,0x41,0x6c,0x28,0xda,0x27,0x1a,0x78,0xd0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x24,0x45,0xe9,0xa6,0x5a,0xa0,0xb0,0x01,0xaf,0x5b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x25,0x09,0xa6,0xf6,0x4a,0xec,0xd5,0x33,0x74,0x35}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x26,0x55,0x1f,0xca,0x70,0xe5,0xbe,0xe3,0xa6,0x33}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2e,0xdb,0x8c,0x24,0x20,0xf2,0x9f,0x7c,0xb4,0xea}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x28,0x21,0xfd,0xd5,0x3c,0x78,0xa5,0xfd,0xcc,0xf4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x28,0xeb,0x35,0xa7,0x6f,0x90,0x83,0x7a,0x1f,0xfd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x29,0x86,0xfb,0xba,0xbc,0x6e,0x6f,0x53,0x89,0xf5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2a,0x25,0x08,0x7a,0xb9,0x56,0xd9,0xe9,0xeb,0x5d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2a,0x8c,0xfd,0xc2,0xc4,0x30,0x05,0x11,0xe8,0x29}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2b,0xb7,0x31,0x96,0xd7,0xd7,0xe6,0x05,0x42,0x1d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2c,0x15,0x79,0x88,0xf6,0xc3,0xd1,0x27,0xa9,0xf5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2c,0x28,0xda,0x1d,0x76,0xa8,0xff,0x18,0x78,0x7d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2c,0x6d,0x3e,0xb2,0x42,0x7e,0x0e,0x8a,0x59,0xe4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2c,0xc1,0xc3,0x15,0x28,0xa5,0x7c,0x5d,0x2c,0x9a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2d,0x1d,0x8d,0x21,0xf4,0x84,0x61,0x62,0x74,0x45}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x2e,0x7c,0xd9,0x21,0x3e,0x4a,0x31,0x4b,0x2e,0x42}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x36,0xea,0xb6,0x80,0x00,0x71,0xbb,0x23,0x51,0x1d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x37,0x38,0x8f,0x26,0xd2,0xa4,0xd5,0x66,0x49,0xf9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x37,0x7b,0x3f,0x74,0x7d,0x12,0x92,0x8b,0x89,0xb6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0x12,0x3f,0x13,0x11,0x5e,0xa1,0x65,0x15,0x86}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0x57,0x42,0x6c,0xf1,0xee,0xdf,0xc3,0x46,0xff}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0x5f,0x17,0x76,0x79,0x1d,0x11,0x42,0x97,0x95}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0xb8,0xbd,0xce,0x0b,0xde,0xa0,0x72,0x99,0x88}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0x9a,0xb7,0x46,0xb3,0x7e,0x05,0x40,0x24,0x5e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x30,0xe4,0x80,0xe9,0xaa,0xd1,0x08,0xe4,0x0c,0xc2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0x3a,0x66,0x7c,0x5e,0xb7,0xf0,0x03,0xbf,0x3f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0x0c,0x29,0x90,0x84,0x7f,0x05,0x62,0xcd,0x7d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0x5d,0x88,0x82,0x83,0x35,0x7b,0x04,0x8d,0x54}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0x9e,0x1a,0x61,0xec,0xb9,0x91,0xaf,0x2c,0x5e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x31,0xe0,0x8a,0xe0,0x9f,0x11,0x44,0xa4,0x49,0xb3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x32,0x22,0x05,0x5d,0xcc,0x69,0x3a,0x50,0xe3,0xdc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x32,0xf3,0xd3,0x15,0x5b,0xdc,0xe9,0x43,0x75,0xa4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x33,0xd6,0x09,0xdd,0xd8,0x37,0x5b,0x75,0xf6,0x29}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x34,0x50,0xf5,0xf6,0xe9,0xb6,0x34,0x31,0x47,0xc2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x34,0xce,0x7c,0xad,0x90,0x12,0x35,0xa6,0xde,0x34}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x34,0xdd,0xa1,0xfb,0x92,0xb3,0xa4,0x56,0x2b,0xc2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x35,0x00,0x24,0x34,0x98,0xee,0x98,0x61,0x05,0xfa}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x35,0x95,0x33,0x45,0x93,0xb2,0xbc,0xda,0xf6,0x42}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x35,0x9d,0x76,0xb9,0x43,0x15,0x85,0xf3,0xe3,0x8f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3e,0xf7,0xb2,0xf2,0x0d,0xb1,0x3e,0xc8,0xe1,0x8d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3f,0x81,0xbd,0x37,0x81,0x58,0x6d,0x6c,0x37,0x83}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0x0b,0x69,0xc4,0x2e,0x74,0xb2,0xe2,0x30,0x2c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0x6c,0x73,0x48,0x3b,0x21,0x10,0xd6,0xc7,0xd3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0xab,0xe2,0xba,0xe7,0xeb,0x15,0xf2,0x9c,0x3d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0xfc,0x75,0x4c,0x4b,0xf5,0x80,0xcc,0xaf,0x2c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0xc1,0xe6,0x48,0x1c,0xaf,0x23,0x3f,0xfc,0xd7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x38,0xcc,0xdb,0xaa,0x90,0x90,0xfd,0x64,0xda,0xd7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x39,0x8f,0xb0,0x65,0xbb,0x21,0x24,0x31,0xd4,0x46}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x39,0xf1,0x7a,0x78,0x36,0x52,0x48,0x52,0x25,0xd9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3a,0x32,0xdf,0x45,0x8e,0x2c,0x8d,0xba,0x3d,0x8d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3a,0x61,0x7b,0xcb,0x1a,0x74,0x88,0xc2,0xd4,0x95}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3a,0x82,0xff,0xb0,0x26,0xb7,0x94,0xb5,0xcb,0x92}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3a,0xdc,0x9a,0x59,0x16,0x0a,0x9c,0x9e,0x28,0x79}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3a,0xf3,0x79,0x26,0x3f,0x70,0x77,0x0c,0xe6,0x10}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3b,0x51,0x4c,0xbd,0x64,0xc9,0x03,0x83,0xd7,0xe0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3b,0x9a,0x32,0x59,0x49,0xe4,0xb9,0x11,0x8a,0xc5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3c,0x17,0xd6,0xd7,0xd5,0x38,0x88,0x81,0xec,0x2d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3c,0x9e,0x97,0x7d,0x90,0x8c,0x49,0xd3,0x62,0xf1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3d,0x3d,0xc9,0x69,0x83,0x8e,0xef,0xfc,0x5d,0x40}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3d,0x6d,0x58,0x6a,0x56,0x54,0x2d,0xb8,0x57,0x0e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3d,0x9d,0xa0,0xa3,0x0d,0x1c,0x63,0x57,0xaf,0xc5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3e,0x6e,0x9d,0x8e,0x67,0xde,0x35,0x79,0xf3,0xae}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x46,0xe8,0x5b,0xd2,0xdb,0x9f,0xc5,0x72,0x8d,0xf0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x40,0x36,0xdd,0xc3,0xb4,0xe7,0x4d,0x57,0xdf,0xe0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x40,0x8a,0x69,0x6c,0xa2,0x98,0x94,0x3e,0x60,0x8e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x40,0x9f,0x9f,0x4c,0xf0,0xa8,0xd2,0x2b,0x2e,0xa1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x41,0x77,0xac,0xbb,0xb4,0xe3,0x0e,0x3a,0x34,0xa3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x41,0xb8,0xb3,0x52,0x0b,0xf5,0x6e,0xa0,0xb1,0x91}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x41,0xce,0x28,0xfc,0xa7,0x16,0x60,0x30,0x0b,0x98}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x42,0x59,0xa9,0xe2,0xee,0x0f,0xea,0xaa,0x83,0x39}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x43,0xf6,0xfa,0x52,0x06,0x3d,0x18,0x5c,0xf6,0xd6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x44,0x36,0xa2,0x4f,0xfa,0x2e,0xf1,0xa2,0xc5,0xe6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x44,0x00,0x69,0xf4,0x4e,0xe0,0xe7,0xf3,0xf8,0xe5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x45,0x0d,0x6e,0x69,0x07,0xf1,0xdf,0x18,0x47,0x5e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x45,0x4b,0xff,0xf2,0xbc,0x9f,0xd5,0xed,0xa3,0xc3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x45,0x4a,0x01,0x0c,0xbf,0x12,0x0d,0xac,0xeb,0x1a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x45,0x65,0x71,0xd9,0x54,0xeb,0x8d,0xac,0xa7,0x8b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x45,0xec,0x68,0x9c,0x0a,0x5d,0x69,0xc3,0x79,0xdf}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x46,0x7b,0xe6,0x39,0xde,0x62,0x9f,0xb3,0x7e,0xee}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4e,0x84,0xfe,0xb2,0x96,0xea,0x76,0xba,0x30,0x57}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4e,0x97,0x15,0x46,0xd4,0x32,0xc7,0x62,0x5a,0xd2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4e,0xa1,0x36,0x28,0x7a,0x18,0x02,0xb9,0x4b,0x3c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4f,0x49,0xac,0x50,0x0d,0xef,0xeb,0xa3,0xf4,0x8b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4f,0x52,0x58,0x8e,0x67,0x84,0xfa,0x6d,0x76,0xf9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4f,0x56,0xad,0x52,0xba,0x0c,0x9e,0x58,0x5c,0xaa}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x48,0x1b,0x5a,0xe6,0x4c,0xc8,0xa4,0x9d,0x95,0x0b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x49,0x1a,0xdd,0x4d,0x98,0x5e,0xef,0x70,0x45,0x90}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x49,0x5c,0x4e,0x97,0x52,0x16,0x5c,0x92,0xbf,0x7a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x49,0x84,0x64,0x79,0x5a,0x7d,0xdc,0xe4,0x76,0x1b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x49,0xc0,0xd0,0x6b,0x92,0xd8,0xf2,0xa4,0x4f,0x2f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4a,0x26,0x6a,0x2c,0x3a,0xe3,0x2a,0x58,0x44,0x66}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4a,0x69,0x5b,0x05,0x25,0xca,0xd2,0xc6,0xfe,0x7b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4a,0xc4,0x57,0x30,0xd1,0xed,0xca,0x4b,0x81,0x05}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4a,0xc8,0x79,0x7b,0x01,0x0e,0xbd,0x05,0xb5,0xa0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4a,0xd3,0x9c,0xf2,0x6c,0x0c,0x23,0x78,0x6e,0x1d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4b,0x85,0xc7,0x40,0x44,0x20,0xd4,0x6f,0xfe,0xa5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4c,0x7b,0x8f,0x35,0x34,0x08,0x83,0x5f,0x1b,0x7f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4c,0x5c,0x07,0x4b,0xcb,0x07,0x2a,0x82,0x1d,0xdc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4c,0x98,0xf3,0x99,0x40,0xc7,0xd0,0x83,0x85,0x51}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4c,0xd5,0x26,0xb9,0x54,0x90,0x72,0xc9,0x7e,0xcb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4d,0x3a,0x3a,0x3b,0x71,0xf3,0xfc,0x34,0x65,0xa2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4d,0xbd,0x9c,0x32,0xe2,0x69,0x02,0x03,0xd2,0x89}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4d,0xc0,0xba,0x9c,0xbf,0xb7,0xec,0x4a,0xc3,0x36}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4e,0x32,0x72,0x6d,0x06,0xe7,0x10,0x25,0x62,0x41}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4e,0x49,0xea,0x29,0xbc,0x40,0xe2,0x7e,0x70,0x8e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x57,0x0c,0xb7,0x4d,0x77,0x6b,0x27,0x30,0xf8,0x53}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x57,0xe9,0x8d,0xa2,0xcc,0xa9,0xa9,0x9c,0x18,0x7a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x52,0xf5,0xb7,0x14,0x06,0xdd,0x14,0x1f,0x1e,0xeb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x53,0x95,0x3d,0x42,0x3e,0x1f,0x1e,0xcc,0x07,0x43}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x53,0xc0,0xba,0x6c,0xfd,0xc0,0xd4,0xe0,0x22,0xb2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x54,0x46,0xf0,0x8e,0xb3,0x85,0xba,0x2e,0xac,0x84}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x54,0x51,0x6f,0x2b,0x29,0xc8,0x23,0x93,0x07,0x66}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x54,0x5f,0xa9,0x9c,0x4c,0xb4,0x5f,0x27,0x50,0x9e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x55,0x71,0x51,0xd9,0x36,0x98,0x09,0xd6,0x3b,0xff}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x56,0x23,0x78,0xa3,0xb1,0x0c,0x7c,0x87,0xd2,0x32}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x56,0x76,0xeb,0x9b,0xff,0xe7,0x47,0x79,0xfb,0x50}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5e,0xed,0xd2,0x89,0x48,0xd5,0x83,0x17,0x6a,0x01}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5f,0x38,0x14,0x4a,0x97,0x39,0xff,0x12,0x07,0xb0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5f,0x7d,0xd3,0x77,0x5b,0x23,0x12,0x40,0xd2,0x49}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5f,0xad,0xd5,0x0c,0x88,0x35,0xa4,0x66,0x97,0xb3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5f,0xc1,0xc2,0x32,0x38,0x2d,0xd4,0x93,0x31,0x81}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5f,0xe4,0xb7,0x48,0x49,0x84,0x02,0x82,0x8a,0x56}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0x00,0x54,0xc2,0xb3,0x71,0xbe,0x34,0x95,0x7a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0x0f,0xef,0xf9,0x57,0x09,0x82,0x6b,0x6e,0x9a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0x61,0xa0,0x7d,0xed,0x7b,0x2a,0x8b,0x6a,0x0e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0xb9,0x66,0xbe,0x0b,0xd7,0xeb,0x86,0x23,0x7d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x58,0xdc,0x52,0x84,0xaf,0x56,0xd3,0xe1,0x7f,0x1f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x59,0x0e,0xf6,0x19,0x6a,0x45,0x5c,0x18,0x6a,0x0e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x59,0x89,0x67,0xa7,0x3f,0x41,0x3e,0x30,0x42,0x11}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x59,0x95,0x50,0xd6,0x2e,0xf7,0xd2,0xe6,0x3a,0x56}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5a,0x2d,0xdc,0xf1,0xa6,0x40,0xbc,0x1f,0xd5,0xb5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5a,0x65,0xf3,0x5a,0x2c,0x66,0x41,0xe8,0x78,0xc0}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5b,0x2a,0x0b,0xec,0x9e,0x05,0x81,0x7a,0x9e,0x08}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5c,0x73,0xff,0x8e,0xc5,0xfe,0x21,0xc1,0x19,0xb3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5d,0x41,0xde,0x3d,0xa1,0x86,0x9b,0x26,0x27,0x11}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5d,0xc5,0xaa,0x3c,0xf7,0xc6,0x2e,0x55,0x9d,0xa5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5e,0x13,0x80,0x8e,0x3c,0x3b,0x13,0xb0,0xc0,0x01}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5e,0x75,0x95,0xb5,0x98,0xc3,0x6d,0x33,0x58,0xba}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x67,0x8e,0x26,0xbd,0x0a,0x43,0x30,0x7d,0xff,0x0f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x60,0xfd,0xbe,0xb9,0x89,0x6c,0x4c,0x72,0x10,0x7b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x60,0xc3,0xb7,0x51,0xf6,0x2f,0x0b,0xa8,0x61,0x21}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x61,0x3c,0x3e,0x12,0x57,0xfb,0x8e,0x36,0xdd,0xa4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x61,0x04,0x55,0x21,0x5d,0x12,0x39,0xfb,0x09,0x49}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x61,0x63,0x52,0x55,0xbf,0xb7,0xa3,0x69,0x3f,0x91}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x62,0x19,0x4a,0x4d,0x64,0xb7,0x65,0x19,0x8e,0x8a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x63,0x71,0x25,0x6d,0x19,0xbd,0x62,0x0d,0x9e,0x95}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x64,0x29,0xe3,0x42,0x71,0x3b,0x3d,0x7c,0xda,0xc7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x65,0xa8,0x2f,0x55,0xcc,0xe3,0x4c,0x84,0xcc,0x3b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x65,0xc7,0x38,0xa4,0xe4,0xd6,0x0b,0x2b,0xed,0xe6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0x10,0x12,0x4f,0x8f,0x44,0x85,0x5d,0x69,0xa9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0x87,0xcf,0x54,0x39,0xbf,0x36,0x12,0x55,0x61}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0xa7,0xe5,0x14,0xd9,0x5d,0x5d,0x9b,0x9c,0xac}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6f,0xe3,0x17,0x08,0xf6,0x24,0x4b,0xa8,0x5f,0x24}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x68,0xa4,0x34,0x41,0x8d,0xb9,0xda,0xd4,0x86,0x59}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x27,0x7b,0x6d,0x0b,0x29,0x5a,0x67,0xd1,0x95}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x57,0x2a,0xd0,0x28,0x58,0xc8,0x75,0xd2,0xd1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x64,0xb2,0xc9,0x15,0xc6,0x0e,0x8b,0x86,0x4f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x8b,0xd2,0x78,0x3f,0x7a,0xf8,0x92,0x8f,0x80}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x9e,0xf9,0x07,0x73,0xd8,0xe8,0x24,0x93,0xcc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0xcb,0x6c,0x41,0x52,0x61,0x20,0x4e,0x77,0x39}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0xf0,0x96,0x3c,0x4c,0x78,0x33,0xd0,0xf0,0x00}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6b,0x59,0x5f,0xe7,0xdd,0x57,0xba,0xc1,0x12,0x51}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6c,0x62,0x5b,0x0d,0x91,0x66,0xd0,0xca,0x10,0x2d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6c,0x62,0xc5,0x19,0x94,0x5b,0xcd,0x20,0xd9,0x73}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6d,0xb8,0x7f,0xac,0x82,0x55,0x27,0xf2,0x01,0xf5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6d,0x95,0x8d,0xd8,0x7b,0x41,0xdc,0x81,0xd4,0x3d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6e,0x38,0xa5,0x11,0x8c,0x64,0x2b,0xc5,0xbe,0x6c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x76,0xbb,0x65,0x0a,0xdf,0x23,0xa2,0x6d,0x4d,0xc8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x76,0x8d,0x46,0x54,0x2a,0xb7,0x9e,0xce,0x74,0x45}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x77,0x30,0x99,0x1c,0x76,0x58,0x64,0x7c,0x2e,0x16}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x71,0x6f,0xc8,0x1a,0xde,0x5b,0xde,0xda,0xcc,0xd5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x72,0x89,0x34,0x3d,0x7c,0x33,0x47,0x01,0x02,0x92}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x74,0x3b,0x0e,0x42,0x30,0x42,0x63,0xa5,0x3e,0x8d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x74,0x2d,0xb6,0x15,0xc8,0x70,0x60,0x25,0x2e,0xe7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x74,0x65,0x8d,0x57,0xdb,0x20,0xa2,0xc1,0xa7,0xbd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x74,0xf9,0x3c,0xb3,0x2d,0xc2,0x18,0xc5,0xcb,0x2a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x75,0x95,0xe1,0x69,0x25,0x99,0xec,0xac,0x00,0xe4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x76,0x3f,0x29,0x6c,0xec,0xd3,0x95,0x7e,0x4e,0x8d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7e,0x9e,0x2f,0x58,0x20,0x23,0xea,0x34,0x78,0x44}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7e,0xaf,0xae,0x18,0x67,0x04,0x98,0x61,0x2f,0xa9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7f,0x84,0xea,0x51,0x31,0xd3,0x46,0x75,0xae,0xbb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x78,0x3e,0x3b,0x74,0x2b,0x6f,0x57,0x06,0x53,0xbb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x78,0x24,0xc1,0x1e,0x6e,0x73,0x93,0xa5,0x08,0xe3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x78,0xc0,0xf5,0x28,0xea,0xf3,0xc2,0x2c,0x6a,0x69}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x79,0x0f,0xd0,0x25,0xd4,0xa5,0xbc,0xcb,0x72,0x51}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7a,0xa9,0x41,0x75,0xf6,0x5f,0x6f,0x83,0x58,0xf1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0x39,0x64,0xaf,0xf5,0x37,0xe7,0x22,0xe0,0x42}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0xc3,0x68,0x1e,0x92,0x7c,0xbb,0x04,0x12,0x0b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0xec,0xf0,0xdb,0x09,0xea,0xdb,0x82,0x5b,0x45}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7d,0x3f,0x6d,0xa4,0xb8,0x8e,0x5f,0xf9,0x5e,0x48}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7d,0xb0,0xb0,0xe2,0xa5,0xa0,0xbd,0xa3,0x9e,0xb7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x86,0x8a,0x76,0xb7,0x13,0xe8,0x74,0x0c,0x54,0x44}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x86,0xd1,0xb0,0x3e,0x88,0x73,0x42,0x0c,0xb0,0xa4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x80,0xfc,0x51,0x3e,0x9b,0x7d,0x42,0x5d,0x63,0x77}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x81,0x49,0x6a,0xef,0x1f,0x06,0xdf,0xc4,0x6c,0x23}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x81,0xf1,0x31,0xce,0x65,0x59,0xc2,0x2e,0x46,0x47}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x82,0x9b,0xbe,0xc4,0x3b,0xbe,0x8d,0x70,0xda,0x1c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x82,0xea,0xb2,0x5e,0x5f,0x7d,0x80,0x2d,0x17,0x81}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x83,0x8c,0x28,0x22,0x33,0xa4,0xc1,0xe8,0xae,0xe6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x84,0x73,0x02,0xdd,0x47,0x8b,0x29,0xda,0xf6,0x2e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x84,0xb0,0x90,0x4a,0x1c,0xf0,0x75,0x2c,0x23,0x12}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x85,0x29,0xc0,0xeb,0x29,0x0b,0x63,0xaa,0x13,0x98}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x85,0x30,0x22,0xa7,0x56,0x23,0x73,0xe0,0x97,0x03}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x85,0x47,0x8d,0x89,0x8e,0x13,0x57,0x5e,0xd7,0xe2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x85,0x6c,0x77,0xc3,0x06,0x03,0x75,0x75,0x63,0xa7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x86,0x29,0x3b,0x0b,0x5e,0xa2,0xd7,0x44,0x80,0xa1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8f,0x3b,0x03,0x68,0x7e,0x45,0x8a,0x33,0xc2,0xcb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8f,0x2f,0x41,0xc7,0xd4,0xe4,0x7a,0xdc,0x18,0x1c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8f,0x80,0xf0,0x76,0x52,0xa2,0x6e,0x1b,0x0f,0x7c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8f,0xb3,0xa3,0x0a,0x54,0xdf,0xd5,0xb3,0x00,0x07}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x88,0x62,0x93,0x14,0x42,0x07,0xab,0xd0,0xff,0x0e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x88,0x90,0x5b,0xa0,0x20,0xb4,0x27,0xe8,0xdf,0x39}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x88,0xdd,0xbb,0x8a,0x6a,0xde,0x55,0x94,0xd5,0x6d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x88,0xea,0xb2,0x3f,0x1e,0x31,0xcc,0xf0,0x3f,0x2e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x89,0x05,0x2d,0x83,0x5f,0x11,0xeb,0xa5,0x9b,0xdd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x89,0x58,0x14,0x63,0xb5,0xcc,0xea,0xdf,0x1f,0x0d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8a,0xd1,0xd5,0x85,0x24,0xe2,0xbf,0xf4,0x37,0x36}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8b,0xa1,0x66,0xb0,0x8f,0x12,0x79,0xdd,0xd4,0xa7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8b,0xc2,0xdb,0xf7,0x90,0x6a,0x11,0x58,0xb0,0xfb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8c,0xab,0x57,0x1a,0x03,0x5a,0x12,0xff,0xfc,0xf5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8d,0x99,0xd1,0xf0,0xe6,0xd9,0xc5,0xff,0xa8,0x73}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x96,0xf0,0x45,0xaa,0xa2,0xe9,0x7b,0x72,0x62,0x56}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x97,0xa3,0x7e,0xe8,0xe8,0x9b,0x1e,0xfe,0x2c,0xc4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x90,0x3c,0xcd,0xc6,0xb8,0x12,0x1e,0x62,0x31,0x58}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x90,0x2a,0x40,0x90,0x92,0x62,0x91,0x56,0x14,0x2e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x90,0x70,0x98,0xf5,0xaf,0x56,0x98,0xb6,0x16,0xdf}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x91,0x23,0x64,0xf3,0x49,0x61,0x3b,0x73,0x9d,0x96}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x91,0xb9,0x56,0x50,0x35,0xd8,0xd3,0x1c,0xd6,0x87}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x91,0xe4,0x65,0x49,0x74,0xcf,0x92,0xa3,0x3f,0xc6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x92,0x71,0x96,0x5a,0xd4,0xf0,0xd0,0x84,0x4f,0x71}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x92,0xb6,0x46,0xee,0x24,0xa0,0xcd,0xb9,0x0c,0xdd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x92,0x9c,0x82,0xbf,0x8e,0x4f,0xd7,0xc7,0x4a,0x9d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x92,0xc9,0xa1,0x01,0xeb,0x52,0xdb,0xbd,0x93,0xf8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x93,0x06,0x3f,0xc3,0xe6,0x73,0x40,0x91,0xb1,0x30}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x93,0xd8,0x7a,0x5d,0x21,0xd0,0x87,0xf5,0x92,0x8d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x94,0x54,0x6c,0x57,0xa4,0x1b,0x74,0xf0,0x7d,0x0b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x94,0x96,0xd4,0xa4,0xed,0x65,0x96,0xbc,0x4a,0xbc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x95,0x3d,0xec,0x1a,0x20,0x97,0xa2,0xa1,0xcd,0xab}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x95,0x1a,0x3a,0xb0,0x29,0x8c,0xcc,0x32,0x80,0xf7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x95,0x47,0xee,0xab,0xa9,0x78,0x17,0xa7,0xed,0x73}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x95,0x68,0x0e,0x9d,0x10,0x5d,0x2d,0xf7,0x6a,0x56}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x95,0xe0,0x9a,0x05,0x94,0x67,0x22,0xc2,0x99,0xf4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9e,0xb9,0xda,0xa3,0xfc,0xd4,0xd1,0xb9,0xb5,0x40}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9f,0x0a,0x17,0x56,0xa6,0xcb,0xda,0x86,0x0f,0x4f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9f,0x17,0xcb,0x57,0x64,0x8a,0x8e,0xf1,0x93,0x4f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9f,0x60,0x23,0xd8,0x31,0xf5,0x3b,0x5d,0x00,0xca}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9f,0xd2,0xb0,0x27,0xc6,0x36,0x2f,0xf9,0x76,0xb8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0x3d,0x24,0x92,0x18,0x0e,0xbe,0x5e,0x37,0x80}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0x2b,0xfa,0x4d,0xf6,0xe3,0xcb,0x8f,0xa7,0xca}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0x2e,0x6e,0xe7,0x52,0xb9,0x59,0xd1,0x70,0x7e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0x15,0x6a,0xb4,0x2e,0x18,0x73,0x15,0xd0,0xb2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0xb9,0x4b,0x45,0x2c,0x9c,0x74,0x95,0x85,0x38}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0xf8,0x24,0xd4,0xa5,0x4c,0xed,0xea,0xb9,0x94}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0xfc,0x5b,0xe1,0x93,0xb3,0x4a,0x82,0xc0,0x94}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0xe6,0x23,0x9d,0x7a,0xed,0x35,0xe6,0x99,0x70}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9a,0x10,0x03,0xfc,0x52,0xa3,0x94,0xb1,0x55,0x1e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9a,0xbd,0xbb,0xf4,0xaa,0xde,0xf7,0xfc,0xee,0x83}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9a,0x8c,0xe7,0x4c,0x13,0xf0,0xa0,0xdf,0xd7,0x18}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9b,0x53,0xdf,0x76,0xd6,0x86,0x7b,0x67,0xa6,0xb2}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9c,0xbd,0x0b,0xef,0xec,0x63,0xe9,0xe6,0xa7,0xb8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9c,0xd2,0x89,0x56,0xf8,0x19,0x83,0x37,0xf7,0xc5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9d,0x9b,0xde,0x57,0xf1,0x06,0xae,0x93,0x0f,0xbd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9d,0xc8,0xce,0xb0,0x94,0x36,0xb8,0x6d,0x13,0x23}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9e,0x11,0x46,0xb7,0x7e,0x5b,0x0a,0x28,0x75,0x71}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9e,0x2b,0xdf,0x5e,0x5e,0x37,0x9a,0x3c,0xc2,0x97}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa7,0x3e,0x5d,0x9e,0xf6,0x87,0xbb,0x23,0x4b,0x8e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa7,0x23,0xf2,0xb4,0xee,0x5c,0x47,0x6b,0x2d,0xa8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa7,0x7b,0xe7,0x14,0x3b,0x66,0x01,0x10,0x16,0xcd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa7,0x61,0xb3,0x07,0x3c,0x83,0xf3,0xcb,0x55,0x71}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa0,0x14,0xbc,0x6f,0x03,0x89,0x2b,0x57,0xde,0xc8}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa1,0xbc,0x70,0x3d,0x1c,0x84,0xc8,0xac,0x8b,0xf5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa2,0x3b,0xdd,0xc1,0xd3,0x1f,0xa2,0xe6,0xee,0x25}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa2,0x23,0xf2,0xee,0xcb,0x9b,0x94,0x0f,0x04,0x21}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa2,0xa2,0x94,0x9e,0xce,0x1a,0xf9,0xcb,0x31,0xc5}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa2,0xfa,0x66,0x69,0x17,0xc7,0xd5,0x01,0x96,0xc6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa3,0x46,0x3f,0xc6,0x49,0xe3,0xc8,0xdd,0xd9,0xdc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa3,0xa3,0x67,0xe4,0xa4,0x3c,0xf0,0xa8,0x9b,0x9b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa3,0xab,0x27,0xeb,0x0b,0x9b,0x40,0xe4,0xc3,0xcb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa4,0x81,0x96,0x0c,0x52,0xde,0x9b,0x8d,0x70,0x78}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa4,0x81,0x99,0x7c,0xcb,0x67,0xcc,0x4c,0x5d,0x4b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa4,0xa5,0xa5,0x10,0x66,0xfc,0x15,0x63,0x0e,0x3d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa4,0xcd,0x88,0xd6,0xdf,0xed,0xab,0xa6,0xe1,0x88}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa6,0x6c,0x01,0x32,0x5f,0x56,0x32,0x72,0x1c,0x2b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xae,0x94,0x31,0x12,0x75,0x92,0xd8,0x32,0x8a,0xd1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaf,0x56,0x76,0xe7,0x35,0xf3,0x5a,0x62,0x9b,0xa3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa8,0xb9,0xc3,0x07,0x95,0x23,0xde,0xe0,0xc6,0x7b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa9,0x6d,0x83,0xa6,0x9c,0xdd,0xae,0x7c,0xd6,0x97}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa9,0xa8,0x9a,0x15,0x5d,0xda,0xe1,0x87,0x2d,0x0e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa9,0xc8,0x44,0xc2,0x1a,0xaf,0x46,0xa0,0xf2,0xf1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaa,0x7d,0xc2,0x0c,0x95,0xe2,0x5b,0x02,0x8e,0x41}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xab,0x00,0x8e,0xd1,0x06,0x26,0x63,0xa5,0x1d,0x49}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xab,0x29,0x85,0x0f,0xf2,0xb8,0x58,0x8f,0xdb,0xbf}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xab,0x98,0x40,0x0a,0x73,0x43,0x6f,0xb6,0x3d,0x8b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xab,0xdd,0x6d,0x5d,0xc5,0x36,0xcb,0x6c,0xc8,0x70}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xac,0x81,0x65,0xa3,0x8b,0xea,0x0b,0x71,0xe4,0x16}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xad,0x1b,0x40,0xc1,0x45,0x64,0xbf,0x24,0x15,0xca}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xad,0x1c,0xc0,0xb4,0x95,0xb5,0x17,0xc0,0xc2,0x41}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xad,0xc4,0xfa,0x8d,0xa6,0xf7,0x40,0x42,0xe7,0xd3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xae,0x2e,0xe4,0x64,0x79,0x05,0x5f,0xb7,0x04,0x14}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb0,0x48,0xe6,0xe8,0x48,0xfa,0xca,0x87,0x78,0x18}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb0,0x6c,0x4a,0x92,0xde,0xd3,0x0d,0x28,0xc4,0x79}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0x41,0x81,0xac,0xde,0xce,0x0b,0x94,0x8a,0x9d}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0x73,0xdf,0x4b,0xab,0xc3,0x7a,0x3c,0x48,0x99}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0xb6,0xc8,0x72,0x86,0xc6,0x34,0x6b,0xef,0x41}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0xd5,0x8e,0xf0,0x22,0x9a,0x8b,0xa6,0xf1,0xfb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb1,0xd8,0x90,0x36,0x0e,0xc6,0x51,0x9c,0x8b,0x93}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb2,0xce,0xea,0x6a,0xd7,0x34,0x30,0x8d,0xdf,0x65}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb2,0xea,0xa2,0xc5,0xeb,0x2a,0x10,0xec,0xeb,0x4e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbe,0xda,0x60,0xee,0xa0,0xf8,0xdd,0x5a,0x11,0xb6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbf,0x7f,0x7f,0x68,0x2c,0x63,0x70,0xba,0xbb,0xf1}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb9,0xaa,0xce,0xfd,0x87,0x35,0x7b,0xee,0x0d,0x40}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb9,0xe5,0xb3,0x2c,0xb6,0x6d,0x91,0x46,0x22,0xad}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xba,0x49,0xd2,0xda,0xb8,0x28,0xe8,0x4d,0x53,0xca}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xba,0xcd,0x40,0x9b,0x0b,0xc6,0x82,0xba,0xc8,0xdd}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbb,0x57,0x4d,0xce,0xa0,0x53,0x4d,0x8f,0xcd,0x4f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbb,0xba,0xc0,0x45,0x0b,0x3d,0x30,0xef,0x86,0x93}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbc,0x80,0x0b,0xa0,0xe3,0xc1,0x9b,0x6b,0xc5,0x17}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbd,0x3a,0xc5,0xd0,0xc3,0x93,0x32,0x55,0x57,0x27}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbd,0x63,0x78,0x09,0xf3,0x85,0x50,0x42,0x0c,0x3a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbd,0xb2,0x78,0xc7,0x06,0x2c,0xe1,0xb8,0x72,0xdc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc7,0x25,0x66,0x48,0x17,0x18,0x9d,0x2d,0x05,0xb4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc7,0x66,0xbe,0x2e,0x08,0xdf,0xba,0xf7,0xae,0x83}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc7,0x6d,0x92,0x43,0x00,0x24,0xe5,0xd6,0x83,0xd3}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc7,0xf7,0x05,0x69,0x99,0x52,0x54,0x77,0x2b,0x1f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc7,0xdd,0x9d,0xe0,0x6d,0xaa,0x03,0xcb,0x9c,0x21}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc0,0x0f,0xf8,0x18,0xb0,0x84,0x66,0x47,0x08,0xe4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc0,0x41,0xc0,0xc5,0x9d,0xef,0x46,0x46,0xae,0x7f}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc1,0x89,0x05,0x1b,0x88,0x6b,0xd7,0x20,0x08,0x9b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc2,0x4e,0xd2,0xd3,0xfd,0x58,0x32,0x14,0x6f,0x87}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc2,0x6d,0xf5,0x40,0x0f,0xbd,0xfb,0x53,0x19,0xc9}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc3,0x3e,0x86,0xb1,0xd5,0x0c,0x5a,0x0e,0x18,0x4e}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc4,0x3a,0x2a,0x49,0xb4,0x72,0xa4,0x2c,0x7b,0x99}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc4,0x44,0x04,0x3a,0x11,0x84,0x47,0x67,0x2a,0x13}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc4,0x45,0x1f,0xbc,0xc9,0xa0,0x32,0x01,0xeb,0xbc}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc4,0x55,0x2a,0xb9,0xbb,0x9b,0x2a,0xe7,0x1c,0x75}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc4,0xdf,0x49,0x72,0xb7,0xed,0xbe,0x9f,0x59,0xfa}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc4,0xe0,0x24,0x19,0x5a,0x39,0xc6,0xbe,0x74,0xee}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc5,0xdc,0x95,0xee,0xec,0x4d,0x25,0xb1,0xa1,0x5a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc6,0x47,0x01,0xca,0x17,0xe1,0x47,0x46,0x9b,0xd6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xce,0xf6,0xda,0x2a,0x7f,0x69,0x90,0xad,0x89,0xe4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xce,0xf1,0x60,0x80,0x76,0xe7,0x9a,0x36,0xdc,0xc7}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcf,0x98,0x18,0x43,0xeb,0x5d,0xd7,0x16,0xf1,0x50}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc8,0x76,0xb8,0x89,0x52,0x6f,0x23,0x93,0xe5,0x24}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc9,0x3e,0xe1,0xbf,0xef,0xc8,0x22,0x97,0xae,0x51}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc9,0x82,0xc3,0xcc,0x29,0x07,0x0b,0x8d,0x6f,0xfb}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc9,0xfe,0x7a,0x81,0x62,0x35,0x52,0xf7,0x02,0x0c}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xca,0x33,0x3a,0xdc,0x87,0x62,0x7a,0xc2,0x1d,0xe6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xca,0x50,0x8d,0xe0,0x82,0x1c,0x59,0x0f,0xef,0x1b}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xca,0xa3,0x66,0x19,0x34,0xac,0xb2,0x0f,0x60,0x9a}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcb,0xb3,0xa0,0x39,0xf6,0x46,0xec,0x5a,0x42,0xc6}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcc,0xc6,0x22,0xb4,0xfc,0xf7,0xff,0xb0,0xa2,0xb4}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcd,0x2e,0x71,0x78,0x7b,0x6d,0x9e,0x61,0x70,0x05}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcd,0x31,0x38,0x94,0x95,0xca,0x44,0xf4,0x65,0x68}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcd,0x61,0xe1,0xbe,0x7b,0x46,0x9c,0x51,0xbf,0x66}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcd,0xac,0xcf,0x18,0x1f,0xa6,0x8f,0x02,0x6a,0x43}, 8333}, + {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xce,0x20,0x1e,0x2c,0x8d,0x2c,0x9e,0xd9,0xa7,0xac}, 8333} }; static SeedSpec6 pnSeed6_test[] = { diff --git a/src/checkqueue.h b/src/checkqueue.h index e3faa1dec0..4ceeb3600a 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -6,13 +6,12 @@ #define BITCOIN_CHECKQUEUE_H #include <sync.h> +#include <tinyformat.h> +#include <util/threadnames.h> #include <algorithm> #include <vector> -#include <boost/thread/condition_variable.hpp> -#include <boost/thread/mutex.hpp> - template <typename T> class CCheckQueueControl; @@ -31,61 +30,64 @@ class CCheckQueue { private: //! Mutex to protect the inner state - boost::mutex mutex; + Mutex m_mutex; //! Worker threads block on this when out of work - boost::condition_variable condWorker; + std::condition_variable m_worker_cv; //! Master thread blocks on this when out of work - boost::condition_variable condMaster; + std::condition_variable m_master_cv; //! The queue of elements to be processed. //! As the order of booleans doesn't matter, it is used as a LIFO (stack) - std::vector<T> queue; + std::vector<T> queue GUARDED_BY(m_mutex); //! The number of workers (including the master) that are idle. - int nIdle; + int nIdle GUARDED_BY(m_mutex){0}; //! The total number of workers (including the master). - int nTotal; + int nTotal GUARDED_BY(m_mutex){0}; //! The temporary evaluation result. - bool fAllOk; + bool fAllOk GUARDED_BY(m_mutex){true}; /** * Number of verifications that haven't completed yet. * This includes elements that are no longer queued, but still in the * worker's own batches. */ - unsigned int nTodo; + unsigned int nTodo GUARDED_BY(m_mutex){0}; //! The maximum number of elements to be processed in one batch - unsigned int nBatchSize; + const unsigned int nBatchSize; + + std::vector<std::thread> m_worker_threads; + bool m_request_stop GUARDED_BY(m_mutex){false}; /** Internal function that does bulk of the verification work. */ - bool Loop(bool fMaster = false) + bool Loop(bool fMaster) { - boost::condition_variable& cond = fMaster ? condMaster : condWorker; + std::condition_variable& cond = fMaster ? m_master_cv : m_worker_cv; std::vector<T> vChecks; vChecks.reserve(nBatchSize); unsigned int nNow = 0; bool fOk = true; do { { - boost::unique_lock<boost::mutex> lock(mutex); + WAIT_LOCK(m_mutex, lock); // first do the clean-up of the previous loop run (allowing us to do it in the same critsect) if (nNow) { fAllOk &= fOk; nTodo -= nNow; if (nTodo == 0 && !fMaster) // We processed the last element; inform the master it can exit and return the result - condMaster.notify_one(); + m_master_cv.notify_one(); } else { // first iteration nTotal++; } // logically, the do loop starts here - while (queue.empty()) { + while (queue.empty() && !m_request_stop) { if (fMaster && nTodo == 0) { nTotal--; bool fRet = fAllOk; @@ -98,6 +100,10 @@ private: cond.wait(lock); // wait nIdle--; } + if (m_request_stop) { + return false; + } + // Decide how many work units to process now. // * Do not try to do everything at once, but aim for increasingly smaller batches so // all workers finish approximately simultaneously. @@ -106,7 +112,7 @@ private: nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1))); vChecks.resize(nNow); for (unsigned int i = 0; i < nNow; i++) { - // We want the lock on the mutex to be as short as possible, so swap jobs from the global + // We want the lock on the m_mutex to be as short as possible, so swap jobs from the global // queue to the local batch vector instead of copying. vChecks[i].swap(queue.back()); queue.pop_back(); @@ -124,40 +130,68 @@ private: public: //! Mutex to ensure only one concurrent CCheckQueueControl - boost::mutex ControlMutex; + Mutex m_control_mutex; //! Create a new check queue - explicit CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), nBatchSize(nBatchSizeIn) {} + explicit CCheckQueue(unsigned int nBatchSizeIn) + : nBatchSize(nBatchSizeIn) + { + } - //! Worker thread - void Thread() + //! Create a pool of new worker threads. + void StartWorkerThreads(const int threads_num) { - Loop(); + { + LOCK(m_mutex); + nIdle = 0; + nTotal = 0; + fAllOk = true; + } + assert(m_worker_threads.empty()); + for (int n = 0; n < threads_num; ++n) { + m_worker_threads.emplace_back([this, n]() { + util::ThreadRename(strprintf("scriptch.%i", n)); + Loop(false /* worker thread */); + }); + } } //! Wait until execution finishes, and return whether all evaluations were successful. bool Wait() { - return Loop(true); + return Loop(true /* master thread */); } //! Add a batch of checks to the queue void Add(std::vector<T>& vChecks) { - boost::unique_lock<boost::mutex> lock(mutex); + LOCK(m_mutex); for (T& check : vChecks) { queue.push_back(T()); check.swap(queue.back()); } nTodo += vChecks.size(); if (vChecks.size() == 1) - condWorker.notify_one(); + m_worker_cv.notify_one(); else if (vChecks.size() > 1) - condWorker.notify_all(); + m_worker_cv.notify_all(); + } + + //! Stop all of the worker threads. + void StopWorkerThreads() + { + WITH_LOCK(m_mutex, m_request_stop = true); + m_worker_cv.notify_all(); + for (std::thread& t : m_worker_threads) { + t.join(); + } + m_worker_threads.clear(); + WITH_LOCK(m_mutex, m_request_stop = false); } ~CCheckQueue() { + assert(m_worker_threads.empty()); } }; @@ -181,7 +215,7 @@ public: { // passed queue is supposed to be unused, or nullptr if (pqueue != nullptr) { - ENTER_CRITICAL_SECTION(pqueue->ControlMutex); + ENTER_CRITICAL_SECTION(pqueue->m_control_mutex); } } @@ -205,7 +239,7 @@ public: if (!fDone) Wait(); if (pqueue != nullptr) { - LEAVE_CRITICAL_SECTION(pqueue->ControlMutex); + LEAVE_CRITICAL_SECTION(pqueue->m_control_mutex); } } }; diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 993967a180..29c38e2d3b 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2018 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -30,8 +30,7 @@ const std::string CLIENT_NAME("Satoshi"); #define BUILD_DESC BUILD_GIT_TAG #define BUILD_SUFFIX "" #else - #define BUILD_DESC "v" STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) \ - "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD) + #define BUILD_DESC "v" STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD) #ifdef BUILD_GIT_COMMIT #define BUILD_SUFFIX "-" BUILD_GIT_COMMIT #elif defined(GIT_COMMIT_ID) @@ -45,10 +44,7 @@ const std::string CLIENT_BUILD(BUILD_DESC BUILD_SUFFIX); static std::string FormatVersion(int nVersion) { - if (nVersion % 100 == 0) - return strprintf("%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100); - else - return strprintf("%d.%d.%d.%d", nVersion / 1000000, (nVersion / 10000) % 100, (nVersion / 100) % 100, nVersion % 100); + return strprintf("%d.%d.%d", nVersion / 10000, (nVersion / 100) % 100, nVersion % 100); } std::string FormatFullVersion() diff --git a/src/clientversion.h b/src/clientversion.h index 363094b696..2da909f829 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,7 +10,7 @@ #endif //HAVE_CONFIG_H // Check that required client information is defined -#if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_REVISION) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR) +#if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR) #error Client version information missing: version is not defined by bitcoin-config.h or in any other way #endif @@ -36,9 +36,8 @@ #include <vector> static const int CLIENT_VERSION = - 1000000 * CLIENT_VERSION_MAJOR - + 10000 * CLIENT_VERSION_MINOR - + 100 * CLIENT_VERSION_REVISION + 10000 * CLIENT_VERSION_MAJOR + + 100 * CLIENT_VERSION_MINOR + 1 * CLIENT_VERSION_BUILD; extern const std::string CLIENT_NAME; diff --git a/src/coins.cpp b/src/coins.cpp index 5de2ed7810..dd84e720e7 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,8 +31,6 @@ bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); } size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); } -SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {} - CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {} size_t CCoinsViewCache::DynamicMemoryUsage() const { diff --git a/src/coins.h b/src/coins.h index a3e241ac90..d2eb42d8cf 100644 --- a/src/coins.h +++ b/src/coins.h @@ -8,11 +8,11 @@ #include <compressor.h> #include <core_memusage.h> -#include <crypto/siphash.h> #include <memusage.h> #include <primitives/transaction.h> #include <serialize.h> #include <uint256.h> +#include <util/hasher.h> #include <assert.h> #include <stdint.h> @@ -82,33 +82,6 @@ public: } }; -class SaltedOutpointHasher -{ -private: - /** Salt */ - const uint64_t k0, k1; - -public: - SaltedOutpointHasher(); - - /** - * This *must* return size_t. With Boost 1.46 on 32-bit systems the - * unordered_map will behave unpredictably if the custom hasher returns a - * uint64_t, resulting in failures when syncing the chain (#4634). - * - * Having the hash noexcept allows libstdc++'s unordered_map to recalculate - * the hash during rehash, so it does not have to cache the value. This - * reduces node's memory by sizeof(size_t). The required recalculation has - * a slight performance penalty (around 1.6%), but this is compensated by - * memory savings of about 9% which allow for a larger dbcache setting. - * - * @see https://gcc.gnu.org/onlinedocs/gcc-9.2.0/libstdc++/manual/manual/unordered_associative.html - */ - size_t operator()(const COutPoint& id) const noexcept { - return SipHashUint256Extra(k0, k1, id.hash, id.n); - } -}; - /** * A Coin in one level of the coins database caching hierarchy. * diff --git a/src/compat.h b/src/compat.h index 0be02cae03..dad14748a2 100644 --- a/src/compat.h +++ b/src/compat.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,11 +18,7 @@ #undef FD_SETSIZE // prevent redefinition compiler warning #endif #define FD_SETSIZE 1024 // max number of fds in fd_set - -#include <winsock2.h> // Must be included before mswsock.h and windows.h - -#include <mswsock.h> -#include <windows.h> +#include <winsock2.h> #include <ws2tcpip.h> #include <stdint.h> #else diff --git a/src/compat/assumptions.h b/src/compat/assumptions.h index 4b0b224c69..301c2d914c 100644 --- a/src/compat/assumptions.h +++ b/src/compat/assumptions.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp index d17de33e86..8a51f310f7 100644 --- a/src/compat/glibc_compat.cpp +++ b/src/compat/glibc_compat.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -54,6 +54,12 @@ __asm(".symver log2f_old,log2f@GLIBC_2.2.5"); __asm(".symver log2f_old,log2f@GLIBC_2.4"); #elif defined(__aarch64__) __asm(".symver log2f_old,log2f@GLIBC_2.17"); +#elif defined(__powerpc64__) +# ifdef WORDS_BIGENDIAN +__asm(".symver log2f_old,log2f@GLIBC_2.3"); +# else +__asm(".symver log2f_old,log2f@GLIBC_2.17"); +# endif #elif defined(__riscv) __asm(".symver log2f_old,log2f@GLIBC_2.27"); #endif diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp index 0367b9a53f..06d0dd6fba 100644 --- a/src/compat/glibc_sanity.cpp +++ b/src/compat/glibc_sanity.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/consensus/params.h b/src/consensus/params.h index 85ab3f61ef..217cb019e1 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,6 +14,7 @@ namespace Consensus { enum DeploymentPos { DEPLOYMENT_TESTDUMMY, + DEPLOYMENT_TAPROOT, // Deployment of Schnorr/Taproot (BIPs 340-342) // NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp MAX_VERSION_BITS_DEPLOYMENTS }; @@ -78,7 +79,9 @@ struct Params { int64_t nPowTargetSpacing; int64_t nPowTargetTimespan; int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } + /** The best chain should have at least this much work */ uint256 nMinimumChainWork; + /** By default assume that the signatures in ancestors of this block are valid */ uint256 defaultAssumeValid; /** diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 9e8e6530f1..f595f16eab 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index e2a9328df8..e78dc9f2a5 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/consensus/validation.h b/src/consensus/validation.h index e007c481df..c4d305434a 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/core_io.h b/src/core_io.h index 80ec80cd50..5469a760ee 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,18 +18,19 @@ class CTransaction; struct CMutableTransaction; class uint256; class UniValue; +class CTxUndo; // core_read.cpp CScript ParseScript(const std::string& s); std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false); -NODISCARD bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true); -NODISCARD bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); +[[nodiscard]] bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true); +[[nodiscard]] bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); /** * Parse a hex string into 256 bits * @param[in] strHex a hex-formatted, 64-character string - * @param[out] result the result of the parasing + * @param[out] result the result of the parsing * @returns true if successful, false if not * * @see ParseHashV for an RPC-oriented version of this @@ -45,6 +46,6 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0); std::string SighashToStr(unsigned char sighash_type); void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void ScriptToUniv(const CScript& script, UniValue& out, bool include_address); -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0); +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr); #endif // BITCOIN_CORE_IO_H diff --git a/src/core_read.cpp b/src/core_read.cpp index 1c0a8a096d..b5fc93886d 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -15,16 +15,15 @@ #include <version.h> #include <boost/algorithm/string/classification.hpp> -#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/split.hpp> #include <algorithm> #include <string> -CScript ParseScript(const std::string& s) -{ - CScript result; +namespace { +opcodetype ParseOpCode(const std::string& s) +{ static std::map<std::string, opcodetype> mapOpNames; if (mapOpNames.empty()) @@ -40,11 +39,23 @@ CScript ParseScript(const std::string& s) continue; mapOpNames[strName] = static_cast<opcodetype>(op); // Convenience: OP_ADD and just ADD are both recognized: - boost::algorithm::replace_first(strName, "OP_", ""); - mapOpNames[strName] = static_cast<opcodetype>(op); + if (strName.compare(0, 3, "OP_") == 0) { // strName starts with "OP_" + mapOpNames[strName.substr(3)] = static_cast<opcodetype>(op); + } } } + auto it = mapOpNames.find(s); + if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode"); + return it->second; +} + +} // namespace + +CScript ParseScript(const std::string& s) +{ + CScript result; + std::vector<std::string> words; boost::algorithm::split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on); @@ -82,14 +93,10 @@ CScript ParseScript(const std::string& s) std::vector<unsigned char> value(w->begin()+1, w->end()-1); result << value; } - else if (mapOpNames.count(*w)) - { - // opcode, e.g. OP_ADD or ADD: - result << mapOpNames[*w]; - } else { - throw std::runtime_error("script parse error"); + // opcode, e.g. OP_ADD or ADD: + result << ParseOpCode(*w); } } @@ -117,41 +124,87 @@ static bool CheckTxScriptsSanity(const CMutableTransaction& tx) return true; } -bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness) +static bool DecodeTx(CMutableTransaction& tx, const std::vector<unsigned char>& tx_data, bool try_no_witness, bool try_witness) { - if (!IsHex(hex_tx)) { - return false; - } + // General strategy: + // - Decode both with extended serialization (which interprets the 0x0001 tag as a marker for + // the presence of witnesses) and with legacy serialization (which interprets the tag as a + // 0-input 1-output incomplete transaction). + // - Restricted by try_no_witness (which disables legacy if false) and try_witness (which + // disables extended if false). + // - Ignore serializations that do not fully consume the hex string. + // - If neither succeeds, fail. + // - If only one succeeds, return that one. + // - If both decode attempts succeed: + // - If only one passes the CheckTxScriptsSanity check, return that one. + // - If neither or both pass CheckTxScriptsSanity, return the extended one. - std::vector<unsigned char> txData(ParseHex(hex_tx)); + CMutableTransaction tx_extended, tx_legacy; + bool ok_extended = false, ok_legacy = false; - if (try_no_witness) { - CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); + // Try decoding with extended serialization support, and remember if the result successfully + // consumes the entire input. + if (try_witness) { + CDataStream ssData(tx_data, SER_NETWORK, PROTOCOL_VERSION); try { - ssData >> tx; - if (ssData.eof() && (!try_witness || CheckTxScriptsSanity(tx))) { - return true; - } + ssData >> tx_extended; + if (ssData.empty()) ok_extended = true; } catch (const std::exception&) { // Fall through. } } - if (try_witness) { - CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); + // Optimization: if extended decoding succeeded and the result passes CheckTxScriptsSanity, + // don't bother decoding the other way. + if (ok_extended && CheckTxScriptsSanity(tx_extended)) { + tx = std::move(tx_extended); + return true; + } + + // Try decoding with legacy serialization, and remember if the result successfully consumes the entire input. + if (try_no_witness) { + CDataStream ssData(tx_data, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS); try { - ssData >> tx; - if (ssData.empty()) { - return true; - } + ssData >> tx_legacy; + if (ssData.empty()) ok_legacy = true; } catch (const std::exception&) { // Fall through. } } + // If legacy decoding succeeded and passes CheckTxScriptsSanity, that's our answer, as we know + // at this point that extended decoding either failed or doesn't pass the sanity check. + if (ok_legacy && CheckTxScriptsSanity(tx_legacy)) { + tx = std::move(tx_legacy); + return true; + } + + // If extended decoding succeeded, and neither decoding passes sanity, return the extended one. + if (ok_extended) { + tx = std::move(tx_extended); + return true; + } + + // If legacy decoding succeeded and extended didn't, return the legacy one. + if (ok_legacy) { + tx = std::move(tx_legacy); + return true; + } + + // If none succeeded, we failed. return false; } +bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness) +{ + if (!IsHex(hex_tx)) { + return false; + } + + std::vector<unsigned char> txData(ParseHex(hex_tx)); + return DecodeTx(tx, txData, try_no_witness, try_witness); +} + bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header) { if (!IsHex(hex_header)) return false; diff --git a/src/core_write.cpp b/src/core_write.cpp index 3980d8cb2e..a3902863d6 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,7 +11,9 @@ #include <script/standard.h> #include <serialize.h> #include <streams.h> +#include <undo.h> #include <univalue.h> +#include <util/check.h> #include <util/system.h> #include <util/strencodings.h> @@ -177,7 +179,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("addresses", a); } -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo) { entry.pushKV("txid", tx.GetHash().GetHex()); entry.pushKV("hash", tx.GetWitnessHash().GetHex()); @@ -189,13 +191,20 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, entry.pushKV("weight", GetTransactionWeight(tx)); entry.pushKV("locktime", (int64_t)tx.nLockTime); - UniValue vin(UniValue::VARR); + UniValue vin{UniValue::VARR}; + + // If available, use Undo data to calculate the fee. Note that txundo == nullptr + // for coinbase transactions and for transactions where undo data is unavailable. + const bool calculate_fee = txundo != nullptr; + CAmount amt_total_in = 0; + CAmount amt_total_out = 0; + for (unsigned int i = 0; i < tx.vin.size(); i++) { const CTxIn& txin = tx.vin[i]; UniValue in(UniValue::VOBJ); - if (tx.IsCoinBase()) + if (tx.IsCoinBase()) { in.pushKV("coinbase", HexStr(txin.scriptSig)); - else { + } else { in.pushKV("txid", txin.prevout.hash.GetHex()); in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); @@ -210,6 +219,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, } in.pushKV("txinwitness", txinwitness); } + if (calculate_fee) { + const CTxOut& prev_txout = txundo->vprevout[i].out; + amt_total_in += prev_txout.nValue; + } in.pushKV("sequence", (int64_t)txin.nSequence); vin.push_back(in); } @@ -228,9 +241,19 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, ScriptPubKeyToUniv(txout.scriptPubKey, o, true); out.pushKV("scriptPubKey", o); vout.push_back(out); + + if (calculate_fee) { + amt_total_out += txout.nValue; + } } entry.pushKV("vout", vout); + if (calculate_fee) { + const CAmount fee = amt_total_in - amt_total_out; + CHECK_NONFATAL(MoneyRange(fee)); + entry.pushKV("fee", ValueFromAmount(fee)); + } + if (!hashBlock.IsNull()) entry.pushKV("blockhash", hashBlock.GetHex()); diff --git a/src/crc32c/.appveyor.yml b/src/crc32c/.appveyor.yml index 7345746750..b23e02e88a 100644 --- a/src/crc32c/.appveyor.yml +++ b/src/crc32c/.appveyor.yml @@ -8,9 +8,9 @@ environment: matrix: # AppVeyor currently has no custom job name feature. # http://help.appveyor.com/discussions/questions/1623-can-i-provide-a-friendly-name-for-jobs - - JOB: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - CMAKE_GENERATOR: Visual Studio 15 2017 + - JOB: Visual Studio 2019 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + CMAKE_GENERATOR: Visual Studio 16 2019 platform: - x86 @@ -24,10 +24,11 @@ build_script: - git submodule update --init --recursive - mkdir build - cd build - - if "%platform%"=="x64" set CMAKE_GENERATOR=%CMAKE_GENERATOR% Win64 + - if "%platform%"=="x86" (set CMAKE_GENERATOR_PLATFORM="Win32") + else (set CMAKE_GENERATOR_PLATFORM="%platform%") - cmake --version - - cmake .. -G "%CMAKE_GENERATOR%" -DCRC32C_USE_GLOG=0 - -DCMAKE_CONFIGURATION_TYPES="%CONFIGURATION%" + - cmake .. -G "%CMAKE_GENERATOR%" -A "%CMAKE_GENERATOR_PLATFORM%" + -DCMAKE_CONFIGURATION_TYPES="%CONFIGURATION%" -DCRC32C_USE_GLOG=0 - cmake --build . --config "%CONFIGURATION%" - cd .. diff --git a/src/crc32c/AUTHORS b/src/crc32c/AUTHORS index 6f1f6871a6..ef9b4ea933 100644 --- a/src/crc32c/AUTHORS +++ b/src/crc32c/AUTHORS @@ -7,3 +7,5 @@ Google Inc. Fangming Fang <Fangming.Fang@arm.com> Vadim Skipin <vadim.skipin@gmail.com> +Rodrigo Tobar <rtobar@icrar.org> +Harry Mallon <hjmallon@gmail.com> diff --git a/src/crc32c/CMakeLists.txt b/src/crc32c/CMakeLists.txt index 111a3e3614..71692d5796 100644 --- a/src/crc32c/CMakeLists.txt +++ b/src/crc32c/CMakeLists.txt @@ -5,15 +5,21 @@ cmake_minimum_required(VERSION 3.1) project(Crc32c VERSION 1.1.0 LANGUAGES C CXX) -# This project can use C11, but will gracefully decay down to C89. -set(CMAKE_C_STANDARD 11) -set(CMAKE_C_STANDARD_REQUIRED OFF) -set(CMAKE_C_EXTENSIONS OFF) - -# This project requires C++11. -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +# C standard can be overridden when this is used as a sub-project. +if(NOT CMAKE_C_STANDARD) + # This project can use C11, but will gracefully decay down to C89. + set(CMAKE_C_STANDARD 11) + set(CMAKE_C_STANDARD_REQUIRED OFF) + set(CMAKE_C_EXTENSIONS OFF) +endif(NOT CMAKE_C_STANDARD) + +# C++ standard can be overridden when this is used as a sub-project. +if(NOT CMAKE_CXX_STANDARD) + # This project requires C++11. + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) +endif(NOT CMAKE_CXX_STANDARD) # https://github.com/izenecloud/cmake/blob/master/SetCompilerWarningAll.cmake if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") @@ -269,7 +275,7 @@ target_sources(crc32c PRIVATE "${PROJECT_BINARY_DIR}/include/crc32c/crc32c_config.h" "src/crc32c_arm64.h" - "src/crc32c_arm64_linux_check.h" + "src/crc32c_arm64_check.h" "src/crc32c_internal.h" "src/crc32c_portable.cc" "src/crc32c_prefetch.h" @@ -405,19 +411,24 @@ if(CRC32C_INSTALL) ) include(CMakePackageConfigHelpers) + configure_package_config_file( + "${PROJECT_NAME}Config.cmake.in" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" + ) write_basic_package_version_file( - "${PROJECT_BINARY_DIR}/Crc32cConfigVersion.cmake" - COMPATIBILITY SameMajorVersion + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + COMPATIBILITY SameMajorVersion ) install( EXPORT Crc32cTargets NAMESPACE Crc32c:: - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Crc32c" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) install( FILES - "Crc32cConfig.cmake" - "${PROJECT_BINARY_DIR}/Crc32cConfigVersion.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Crc32c" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" ) endif(CRC32C_INSTALL) diff --git a/src/crc32c/Crc32cConfig.cmake b/src/crc32c/Crc32cConfig.cmake.in index 4d6057ec26..c6b8fc7913 100644 --- a/src/crc32c/Crc32cConfig.cmake +++ b/src/crc32c/Crc32cConfig.cmake.in @@ -2,4 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. See the AUTHORS file for names of contributors. +@PACKAGE_INIT@ + include("${CMAKE_CURRENT_LIST_DIR}/Crc32cTargets.cmake") + +check_required_components(Crc32c) diff --git a/src/crc32c/src/crc32c.cc b/src/crc32c/src/crc32c.cc index 4d3018af47..804133bc17 100644 --- a/src/crc32c/src/crc32c.cc +++ b/src/crc32c/src/crc32c.cc @@ -8,7 +8,7 @@ #include <cstdint> #include "./crc32c_arm64.h" -#include "./crc32c_arm64_linux_check.h" +#include "./crc32c_arm64_check.h" #include "./crc32c_internal.h" #include "./crc32c_sse42.h" #include "./crc32c_sse42_check.h" @@ -20,8 +20,8 @@ uint32_t Extend(uint32_t crc, const uint8_t* data, size_t count) { static bool can_use_sse42 = CanUseSse42(); if (can_use_sse42) return ExtendSse42(crc, data, count); #elif HAVE_ARM64_CRC32C - static bool can_use_arm_linux = CanUseArm64Linux(); - if (can_use_arm_linux) return ExtendArm64(crc, data, count); + static bool can_use_arm64_crc32 = CanUseArm64Crc32(); + if (can_use_arm64_crc32) return ExtendArm64(crc, data, count); #endif // HAVE_SSE42 && (defined(_M_X64) || defined(__x86_64__)) return ExtendPortable(crc, data, count); diff --git a/src/crc32c/src/crc32c_arm64.cc b/src/crc32c/src/crc32c_arm64.cc index b872245f95..1da04ed34a 100644 --- a/src/crc32c/src/crc32c_arm64.cc +++ b/src/crc32c/src/crc32c_arm64.cc @@ -64,7 +64,7 @@ namespace crc32c { -uint32_t ExtendArm64(uint32_t crc, const uint8_t *buf, size_t size) { +uint32_t ExtendArm64(uint32_t crc, const uint8_t *data, size_t size) { int64_t length = size; uint32_t crc0, crc1, crc2, crc3; uint64_t t0, t1, t2; @@ -74,7 +74,6 @@ uint32_t ExtendArm64(uint32_t crc, const uint8_t *buf, size_t size) { const poly64_t k0 = 0x8d96551c, k1 = 0xbd6f81f8, k2 = 0xdcb17aa4; crc = crc ^ kCRC32Xor; - const uint8_t *p = reinterpret_cast<const uint8_t *>(buf); while (length >= KBYTES) { crc0 = crc; @@ -83,14 +82,14 @@ uint32_t ExtendArm64(uint32_t crc, const uint8_t *buf, size_t size) { crc3 = 0; // Process 1024 bytes in parallel. - CRC32C1024BYTES(p); + CRC32C1024BYTES(data); // Merge the 4 partial CRC32C values. t2 = (uint64_t)vmull_p64(crc2, k2); t1 = (uint64_t)vmull_p64(crc1, k1); t0 = (uint64_t)vmull_p64(crc0, k0); - crc = __crc32cd(crc3, *(uint64_t *)p); - p += sizeof(uint64_t); + crc = __crc32cd(crc3, *(uint64_t *)data); + data += sizeof(uint64_t); crc ^= __crc32cd(0, t2); crc ^= __crc32cd(0, t1); crc ^= __crc32cd(0, t0); @@ -99,23 +98,23 @@ uint32_t ExtendArm64(uint32_t crc, const uint8_t *buf, size_t size) { } while (length >= 8) { - crc = __crc32cd(crc, *(uint64_t *)p); - p += 8; + crc = __crc32cd(crc, *(uint64_t *)data); + data += 8; length -= 8; } if (length & 4) { - crc = __crc32cw(crc, *(uint32_t *)p); - p += 4; + crc = __crc32cw(crc, *(uint32_t *)data); + data += 4; } if (length & 2) { - crc = __crc32ch(crc, *(uint16_t *)p); - p += 2; + crc = __crc32ch(crc, *(uint16_t *)data); + data += 2; } if (length & 1) { - crc = __crc32cb(crc, *p); + crc = __crc32cb(crc, *data); } return crc ^ kCRC32Xor; diff --git a/src/crc32c/src/crc32c_arm64.h b/src/crc32c/src/crc32c_arm64.h index 100cd56ec8..e093687ddc 100644 --- a/src/crc32c/src/crc32c_arm64.h +++ b/src/crc32c/src/crc32c_arm64.h @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. -// Linux-specific code checking the availability for ARM CRC32C instructions. +// ARM-specific code -#ifndef CRC32C_CRC32C_ARM_LINUX_H_ -#define CRC32C_CRC32C_ARM_LINUX_H_ +#ifndef CRC32C_CRC32C_ARM_H_ +#define CRC32C_CRC32C_ARM_H_ #include <cstddef> #include <cstdint> @@ -24,4 +24,4 @@ uint32_t ExtendArm64(uint32_t crc, const uint8_t* data, size_t count); #endif // HAVE_ARM64_CRC32C -#endif // CRC32C_CRC32C_ARM_LINUX_H_ +#endif // CRC32C_CRC32C_ARM_H_ diff --git a/src/crc32c/src/crc32c_arm64_linux_check.h b/src/crc32c/src/crc32c_arm64_check.h index 1a20a757bb..62a07aba09 100644 --- a/src/crc32c/src/crc32c_arm64_linux_check.h +++ b/src/crc32c/src/crc32c_arm64_check.h @@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. See the AUTHORS file for names of contributors. -// ARM Linux-specific code checking for the availability of CRC32C instructions. +// ARM-specific code checking for the availability of CRC32C instructions. -#ifndef CRC32C_CRC32C_ARM_LINUX_CHECK_H_ -#define CRC32C_CRC32C_ARM_LINUX_CHECK_H_ - -// X86-specific code checking for the availability of SSE4.2 instructions. +#ifndef CRC32C_CRC32C_ARM_CHECK_H_ +#define CRC32C_CRC32C_ARM_CHECK_H_ #include <cstddef> #include <cstdint> @@ -18,6 +16,7 @@ #if HAVE_ARM64_CRC32C +#ifdef __linux__ #if HAVE_STRONG_GETAUXVAL #include <sys/auxv.h> #elif HAVE_WEAK_GETAUXVAL @@ -27,17 +26,28 @@ extern "C" unsigned long getauxval(unsigned long type) __attribute__((weak)); #define AT_HWCAP 16 #endif // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL +#endif // defined (__linux__) + +#ifdef __APPLE__ +#include <sys/types.h> +#include <sys/sysctl.h> +#endif // defined (__APPLE__) namespace crc32c { -inline bool CanUseArm64Linux() { -#if HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL +inline bool CanUseArm64Crc32() { +#if defined (__linux__) && (HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL) // From 'arch/arm64/include/uapi/asm/hwcap.h' in Linux kernel source code. constexpr unsigned long kHWCAP_PMULL = 1 << 4; constexpr unsigned long kHWCAP_CRC32 = 1 << 7; unsigned long hwcap = (&getauxval != nullptr) ? getauxval(AT_HWCAP) : 0; return (hwcap & (kHWCAP_PMULL | kHWCAP_CRC32)) == (kHWCAP_PMULL | kHWCAP_CRC32); +#elif defined(__APPLE__) + int val = 0; + size_t len = sizeof(val); + return sysctlbyname("hw.optional.armv8_crc32", &val, &len, nullptr, 0) == 0 + && val != 0; #else return false; #endif // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL @@ -47,4 +57,4 @@ inline bool CanUseArm64Linux() { #endif // HAVE_ARM64_CRC32C -#endif // CRC32C_CRC32C_ARM_LINUX_CHECK_H_ +#endif // CRC32C_CRC32C_ARM_CHECK_H_ diff --git a/src/crc32c/src/crc32c_benchmark.cc b/src/crc32c/src/crc32c_benchmark.cc index c464304b3f..51194b370a 100644 --- a/src/crc32c/src/crc32c_benchmark.cc +++ b/src/crc32c/src/crc32c_benchmark.cc @@ -16,7 +16,7 @@ #endif // CRC32C_TESTS_BUILT_WITH_GLOG #include "./crc32c_arm64.h" -#include "./crc32c_arm64_linux_check.h" +#include "./crc32c_arm64_check.h" #include "./crc32c_internal.h" #include "./crc32c_sse42.h" #include "./crc32c_sse42_check.h" @@ -58,8 +58,8 @@ BENCHMARK_REGISTER_F(CRC32CBenchmark, Portable) #if HAVE_ARM64_CRC32C -BENCHMARK_DEFINE_F(CRC32CBenchmark, ArmLinux)(benchmark::State& state) { - if (!crc32c::CanUseArm64Linux()) { +BENCHMARK_DEFINE_F(CRC32CBenchmark, ArmCRC32C)(benchmark::State& state) { + if (!crc32c::CanUseArm64Crc32()) { state.SkipWithError("ARM CRC32C instructions not available or not enabled"); return; } @@ -69,7 +69,7 @@ BENCHMARK_DEFINE_F(CRC32CBenchmark, ArmLinux)(benchmark::State& state) { crc = crc32c::ExtendArm64(crc, block_buffer_, block_size_); state.SetBytesProcessed(state.iterations() * block_size_); } -BENCHMARK_REGISTER_F(CRC32CBenchmark, ArmLinux) +BENCHMARK_REGISTER_F(CRC32CBenchmark, ArmCRC32C) ->RangeMultiplier(16) ->Range(256, 16777216); // Block size. diff --git a/src/crc32c/src/crc32c_read_le.h b/src/crc32c/src/crc32c_read_le.h index 3bd45fe3aa..673a2a0db7 100644 --- a/src/crc32c/src/crc32c_read_le.h +++ b/src/crc32c/src/crc32c_read_le.h @@ -32,14 +32,14 @@ inline uint32_t ReadUint32LE(const uint8_t* buffer) { // Reads a little-endian 64-bit integer from a 64-bit-aligned buffer. inline uint64_t ReadUint64LE(const uint8_t* buffer) { #if BYTE_ORDER_BIG_ENDIAN - return ((static_cast<uint32_t>(static_cast<uint8_t>(buffer[0]))) | - (static_cast<uint32_t>(static_cast<uint8_t>(buffer[1])) << 8) | - (static_cast<uint32_t>(static_cast<uint8_t>(buffer[2])) << 16) | - (static_cast<uint32_t>(static_cast<uint8_t>(buffer[3])) << 24) | - (static_cast<uint32_t>(static_cast<uint8_t>(buffer[4])) << 32) | - (static_cast<uint32_t>(static_cast<uint8_t>(buffer[5])) << 40) | - (static_cast<uint32_t>(static_cast<uint8_t>(buffer[6])) << 48) | - (static_cast<uint32_t>(static_cast<uint8_t>(buffer[7])) << 56)); + return ((static_cast<uint64_t>(static_cast<uint8_t>(buffer[0]))) | + (static_cast<uint64_t>(static_cast<uint8_t>(buffer[1])) << 8) | + (static_cast<uint64_t>(static_cast<uint8_t>(buffer[2])) << 16) | + (static_cast<uint64_t>(static_cast<uint8_t>(buffer[3])) << 24) | + (static_cast<uint64_t>(static_cast<uint8_t>(buffer[4])) << 32) | + (static_cast<uint64_t>(static_cast<uint8_t>(buffer[5])) << 40) | + (static_cast<uint64_t>(static_cast<uint8_t>(buffer[6])) << 48) | + (static_cast<uint64_t>(static_cast<uint8_t>(buffer[7])) << 56)); #else // !BYTE_ORDER_BIG_ENDIAN uint64_t result; // This should be optimized to a single instruction. diff --git a/src/crypto/chacha_poly_aead.h b/src/crypto/chacha_poly_aead.h index b3ba781cdd..0afe8fcc14 100644 --- a/src/crypto/chacha_poly_aead.h +++ b/src/crypto/chacha_poly_aead.h @@ -17,12 +17,12 @@ static constexpr int AAD_PACKAGES_PER_ROUND = 21; /* 64 / 3 round down*/ /* A AEAD class for ChaCha20-Poly1305@bitcoin. * * ChaCha20 is a stream cipher designed by Daniel Bernstein and described in - * <ref>[http://cr.yp.to/chacha/chacha-20080128.pdf ChaCha20]</ref>. It operates + * <ref>[https://cr.yp.to/chacha/chacha-20080128.pdf ChaCha20]</ref>. It operates * by permuting 128 fixed bits, 128 or 256 bits of key, a 64 bit nonce and a 64 * bit counter into 64 bytes of output. This output is used as a keystream, with * any unused bytes simply discarded. * - * Poly1305 <ref>[http://cr.yp.to/mac/poly1305-20050329.pdf Poly1305]</ref>, also + * Poly1305 <ref>[https://cr.yp.to/mac/poly1305-20050329.pdf Poly1305]</ref>, also * by Daniel Bernstein, is a one-time Carter-Wegman MAC that computes a 128 bit * integrity tag given a message and a single-use 256 bit secret key. * diff --git a/src/crypto/common.h b/src/crypto/common.h index c1acf8b22e..dc12ed9942 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp new file mode 100644 index 0000000000..fbd14f9325 --- /dev/null +++ b/src/crypto/muhash.cpp @@ -0,0 +1,338 @@ +// Copyright (c) 2017-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <crypto/muhash.h> + +#include <crypto/chacha20.h> +#include <crypto/common.h> +#include <hash.h> + +#include <cassert> +#include <cstdio> +#include <limits> + +namespace { + +using limb_t = Num3072::limb_t; +using double_limb_t = Num3072::double_limb_t; +constexpr int LIMB_SIZE = Num3072::LIMB_SIZE; +constexpr int LIMBS = Num3072::LIMBS; +/** 2^3072 - 1103717, the largest 3072-bit safe prime number, is used as the modulus. */ +constexpr limb_t MAX_PRIME_DIFF = 1103717; + +/** Extract the lowest limb of [c0,c1,c2] into n, and left shift the number by 1 limb. */ +inline void extract3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& n) +{ + n = c0; + c0 = c1; + c1 = c2; + c2 = 0; +} + +/** [c0,c1] = a * b */ +inline void mul(limb_t& c0, limb_t& c1, const limb_t& a, const limb_t& b) +{ + double_limb_t t = (double_limb_t)a * b; + c1 = t >> LIMB_SIZE; + c0 = t; +} + +/* [c0,c1,c2] += n * [d0,d1,d2]. c2 is 0 initially */ +inline void mulnadd3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& d0, limb_t& d1, limb_t& d2, const limb_t& n) +{ + double_limb_t t = (double_limb_t)d0 * n + c0; + c0 = t; + t >>= LIMB_SIZE; + t += (double_limb_t)d1 * n + c1; + c1 = t; + t >>= LIMB_SIZE; + c2 = t + d2 * n; +} + +/* [c0,c1] *= n */ +inline void muln2(limb_t& c0, limb_t& c1, const limb_t& n) +{ + double_limb_t t = (double_limb_t)c0 * n; + c0 = t; + t >>= LIMB_SIZE; + t += (double_limb_t)c1 * n; + c1 = t; +} + +/** [c0,c1,c2] += a * b */ +inline void muladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b) +{ + double_limb_t t = (double_limb_t)a * b; + limb_t th = t >> LIMB_SIZE; + limb_t tl = t; + + c0 += tl; + th += (c0 < tl) ? 1 : 0; + c1 += th; + c2 += (c1 < th) ? 1 : 0; +} + +/** [c0,c1,c2] += 2 * a * b */ +inline void muldbladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b) +{ + double_limb_t t = (double_limb_t)a * b; + limb_t th = t >> LIMB_SIZE; + limb_t tl = t; + + c0 += tl; + limb_t tt = th + ((c0 < tl) ? 1 : 0); + c1 += tt; + c2 += (c1 < tt) ? 1 : 0; + c0 += tl; + th += (c0 < tl) ? 1 : 0; + c1 += th; + c2 += (c1 < th) ? 1 : 0; +} + +/** + * Add limb a to [c0,c1]: [c0,c1] += a. Then extract the lowest + * limb of [c0,c1] into n, and left shift the number by 1 limb. + * */ +inline void addnextract2(limb_t& c0, limb_t& c1, const limb_t& a, limb_t& n) +{ + limb_t c2 = 0; + + // add + c0 += a; + if (c0 < a) { + c1 += 1; + + // Handle case when c1 has overflown + if (c1 == 0) + c2 = 1; + } + + // extract + n = c0; + c0 = c1; + c1 = c2; +} + +/** in_out = in_out^(2^sq) * mul */ +inline void square_n_mul(Num3072& in_out, const int sq, const Num3072& mul) +{ + for (int j = 0; j < sq; ++j) in_out.Square(); + in_out.Multiply(mul); +} + +} // namespace + +/** Indicates wether d is larger than the modulus. */ +bool Num3072::IsOverflow() const +{ + if (this->limbs[0] <= std::numeric_limits<limb_t>::max() - MAX_PRIME_DIFF) return false; + for (int i = 1; i < LIMBS; ++i) { + if (this->limbs[i] != std::numeric_limits<limb_t>::max()) return false; + } + return true; +} + +void Num3072::FullReduce() +{ + limb_t c0 = MAX_PRIME_DIFF; + limb_t c1 = 0; + for (int i = 0; i < LIMBS; ++i) { + addnextract2(c0, c1, this->limbs[i], this->limbs[i]); + } +} + +Num3072 Num3072::GetInverse() const +{ + // For fast exponentiation a sliding window exponentiation with repunit + // precomputation is utilized. See "Fast Point Decompression for Standard + // Elliptic Curves" (Brumley, Järvinen, 2008). + + Num3072 p[12]; // p[i] = a^(2^(2^i)-1) + Num3072 out; + + p[0] = *this; + + for (int i = 0; i < 11; ++i) { + p[i + 1] = p[i]; + for (int j = 0; j < (1 << i); ++j) p[i + 1].Square(); + p[i + 1].Multiply(p[i]); + } + + out = p[11]; + + square_n_mul(out, 512, p[9]); + square_n_mul(out, 256, p[8]); + square_n_mul(out, 128, p[7]); + square_n_mul(out, 64, p[6]); + square_n_mul(out, 32, p[5]); + square_n_mul(out, 8, p[3]); + square_n_mul(out, 2, p[1]); + square_n_mul(out, 1, p[0]); + square_n_mul(out, 5, p[2]); + square_n_mul(out, 3, p[0]); + square_n_mul(out, 2, p[0]); + square_n_mul(out, 4, p[0]); + square_n_mul(out, 4, p[1]); + square_n_mul(out, 3, p[0]); + + return out; +} + +void Num3072::Multiply(const Num3072& a) +{ + limb_t c0 = 0, c1 = 0, c2 = 0; + Num3072 tmp; + + /* Compute limbs 0..N-2 of this*a into tmp, including one reduction. */ + for (int j = 0; j < LIMBS - 1; ++j) { + limb_t d0 = 0, d1 = 0, d2 = 0; + mul(d0, d1, this->limbs[1 + j], a.limbs[LIMBS + j - (1 + j)]); + for (int i = 2 + j; i < LIMBS; ++i) muladd3(d0, d1, d2, this->limbs[i], a.limbs[LIMBS + j - i]); + mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF); + for (int i = 0; i < j + 1; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[j - i]); + extract3(c0, c1, c2, tmp.limbs[j]); + } + + /* Compute limb N-1 of a*b into tmp. */ + assert(c2 == 0); + for (int i = 0; i < LIMBS; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[LIMBS - 1 - i]); + extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]); + + /* Perform a second reduction. */ + muln2(c0, c1, MAX_PRIME_DIFF); + for (int j = 0; j < LIMBS; ++j) { + addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]); + } + + assert(c1 == 0); + assert(c0 == 0 || c0 == 1); + + /* Perform up to two more reductions if the internal state has already + * overflown the MAX of Num3072 or if it is larger than the modulus or + * if both are the case. + * */ + if (this->IsOverflow()) this->FullReduce(); + if (c0) this->FullReduce(); +} + +void Num3072::Square() +{ + limb_t c0 = 0, c1 = 0, c2 = 0; + Num3072 tmp; + + /* Compute limbs 0..N-2 of this*this into tmp, including one reduction. */ + for (int j = 0; j < LIMBS - 1; ++j) { + limb_t d0 = 0, d1 = 0, d2 = 0; + for (int i = 0; i < (LIMBS - 1 - j) / 2; ++i) muldbladd3(d0, d1, d2, this->limbs[i + j + 1], this->limbs[LIMBS - 1 - i]); + if ((j + 1) & 1) muladd3(d0, d1, d2, this->limbs[(LIMBS - 1 - j) / 2 + j + 1], this->limbs[LIMBS - 1 - (LIMBS - 1 - j) / 2]); + mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF); + for (int i = 0; i < (j + 1) / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[j - i]); + if ((j + 1) & 1) muladd3(c0, c1, c2, this->limbs[(j + 1) / 2], this->limbs[j - (j + 1) / 2]); + extract3(c0, c1, c2, tmp.limbs[j]); + } + + assert(c2 == 0); + for (int i = 0; i < LIMBS / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[LIMBS - 1 - i]); + extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]); + + /* Perform a second reduction. */ + muln2(c0, c1, MAX_PRIME_DIFF); + for (int j = 0; j < LIMBS; ++j) { + addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]); + } + + assert(c1 == 0); + assert(c0 == 0 || c0 == 1); + + /* Perform up to two more reductions if the internal state has already + * overflown the MAX of Num3072 or if it is larger than the modulus or + * if both are the case. + * */ + if (this->IsOverflow()) this->FullReduce(); + if (c0) this->FullReduce(); +} + +void Num3072::SetToOne() +{ + this->limbs[0] = 1; + for (int i = 1; i < LIMBS; ++i) this->limbs[i] = 0; +} + +void Num3072::Divide(const Num3072& a) +{ + if (this->IsOverflow()) this->FullReduce(); + + Num3072 inv{}; + if (a.IsOverflow()) { + Num3072 b = a; + b.FullReduce(); + inv = b.GetInverse(); + } else { + inv = a.GetInverse(); + } + + this->Multiply(inv); + if (this->IsOverflow()) this->FullReduce(); +} + +Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) { + Num3072 out{}; + uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256(); + unsigned char tmp[BYTE_SIZE]; + ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, BYTE_SIZE); + for (int i = 0; i < LIMBS; ++i) { + if (sizeof(limb_t) == 4) { + out.limbs[i] = ReadLE32(tmp + 4 * i); + } else if (sizeof(limb_t) == 8) { + out.limbs[i] = ReadLE64(tmp + 8 * i); + } + } + return out; +} + +MuHash3072::MuHash3072(Span<const unsigned char> in) noexcept +{ + m_numerator = ToNum3072(in); +} + +void MuHash3072::Finalize(uint256& out) noexcept +{ + m_numerator.Divide(m_denominator); + m_denominator.SetToOne(); // Needed to keep the MuHash object valid + + unsigned char data[384]; + for (int i = 0; i < LIMBS; ++i) { + if (sizeof(limb_t) == 4) { + WriteLE32(data + i * 4, m_numerator.limbs[i]); + } else if (sizeof(limb_t) == 8) { + WriteLE64(data + i * 8, m_numerator.limbs[i]); + } + } + + out = (CHashWriter(SER_DISK, 0) << data).GetSHA256(); +} + +MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept +{ + m_numerator.Multiply(mul.m_numerator); + m_denominator.Multiply(mul.m_denominator); + return *this; +} + +MuHash3072& MuHash3072::operator/=(const MuHash3072& div) noexcept +{ + m_numerator.Multiply(div.m_denominator); + m_denominator.Multiply(div.m_numerator); + return *this; +} + +MuHash3072& MuHash3072::Insert(Span<const unsigned char> in) noexcept { + m_numerator.Multiply(ToNum3072(in)); + return *this; +} + +MuHash3072& MuHash3072::Remove(Span<const unsigned char> in) noexcept { + m_numerator.Divide(ToNum3072(in)); + return *this; +} diff --git a/src/crypto/muhash.h b/src/crypto/muhash.h new file mode 100644 index 0000000000..0c710007c4 --- /dev/null +++ b/src/crypto/muhash.h @@ -0,0 +1,130 @@ +// Copyright (c) 2017-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CRYPTO_MUHASH_H +#define BITCOIN_CRYPTO_MUHASH_H + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <serialize.h> +#include <uint256.h> + +#include <stdint.h> + +class Num3072 +{ +private: + void FullReduce(); + bool IsOverflow() const; + Num3072 GetInverse() const; + +public: + +#ifdef HAVE___INT128 + typedef unsigned __int128 double_limb_t; + typedef uint64_t limb_t; + static constexpr int LIMBS = 48; + static constexpr int LIMB_SIZE = 64; +#else + typedef uint64_t double_limb_t; + typedef uint32_t limb_t; + static constexpr int LIMBS = 96; + static constexpr int LIMB_SIZE = 32; +#endif + limb_t limbs[LIMBS]; + + // Sanity check for Num3072 constants + static_assert(LIMB_SIZE * LIMBS == 3072, "Num3072 isn't 3072 bits"); + static_assert(sizeof(double_limb_t) == sizeof(limb_t) * 2, "bad size for double_limb_t"); + static_assert(sizeof(limb_t) * 8 == LIMB_SIZE, "LIMB_SIZE is incorrect"); + + // Hard coded values in MuHash3072 constructor and Finalize + static_assert(sizeof(limb_t) == 4 || sizeof(limb_t) == 8, "bad size for limb_t"); + + void Multiply(const Num3072& a); + void Divide(const Num3072& a); + void SetToOne(); + void Square(); + + Num3072() { this->SetToOne(); }; + + SERIALIZE_METHODS(Num3072, obj) + { + for (auto& limb : obj.limbs) { + READWRITE(limb); + } + } +}; + +/** A class representing MuHash sets + * + * MuHash is a hashing algorithm that supports adding set elements in any + * order but also deleting in any order. As a result, it can maintain a + * running sum for a set of data as a whole, and add/remove when data + * is added to or removed from it. A downside of MuHash is that computing + * an inverse is relatively expensive. This is solved by representing + * the running value as a fraction, and multiplying added elements into + * the numerator and removed elements into the denominator. Only when the + * final hash is desired, a single modular inverse and multiplication is + * needed to combine the two. The combination is also run on serialization + * to allow for space-efficient storage on disk. + * + * As the update operations are also associative, H(a)+H(b)+H(c)+H(d) can + * in fact be computed as (H(a)+H(b)) + (H(c)+H(d)). This implies that + * all of this is perfectly parallellizable: each thread can process an + * arbitrary subset of the update operations, allowing them to be + * efficiently combined later. + * + * Muhash does not support checking if an element is already part of the + * set. That is why this class does not enforce the use of a set as the + * data it represents because there is no efficient way to do so. + * It is possible to add elements more than once and also to remove + * elements that have not been added before. However, this implementation + * is intended to represent a set of elements. + * + * See also https://cseweb.ucsd.edu/~mihir/papers/inchash.pdf and + * https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-May/014337.html. + */ +class MuHash3072 +{ +private: + static constexpr size_t BYTE_SIZE = 384; + + Num3072 m_numerator; + Num3072 m_denominator; + + Num3072 ToNum3072(Span<const unsigned char> in); + +public: + /* The empty set. */ + MuHash3072() noexcept {}; + + /* A singleton with variable sized data in it. */ + explicit MuHash3072(Span<const unsigned char> in) noexcept; + + /* Insert a single piece of data into the set. */ + MuHash3072& Insert(Span<const unsigned char> in) noexcept; + + /* Remove a single piece of data from the set. */ + MuHash3072& Remove(Span<const unsigned char> in) noexcept; + + /* Multiply (resulting in a hash for the union of the sets) */ + MuHash3072& operator*=(const MuHash3072& mul) noexcept; + + /* Divide (resulting in a hash for the difference of the sets) */ + MuHash3072& operator/=(const MuHash3072& div) noexcept; + + /* Finalize into a 32-byte hash. Does not change this object's value. */ + void Finalize(uint256& out) noexcept; + + SERIALIZE_METHODS(MuHash3072, obj) + { + READWRITE(obj.m_numerator); + READWRITE(obj.m_denominator); + } +}; + +#endif // BITCOIN_CRYPTO_MUHASH_H diff --git a/src/crypto/sha256_shani.cpp b/src/crypto/sha256_shani.cpp index 3473f6e39f..4f4d5b5837 100644 --- a/src/crypto/sha256_shani.cpp +++ b/src/crypto/sha256_shani.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/crypto/sha256_sse4.cpp b/src/crypto/sha256_sse4.cpp index 89f529a3ab..143752c7cf 100644 --- a/src/crypto/sha256_sse4.cpp +++ b/src/crypto/sha256_sse4.cpp @@ -1001,7 +1001,7 @@ void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks) ; This code is described in an Intel White-Paper: ; "Fast SHA-256 Implementations on Intel Architecture Processors" ; -; To find it, surf to http://www.intel.com/p/en_US/embedded +; To find it, surf to https://www.intel.com/p/en_US/embedded ; and search for that title. ; The paper is expected to be released roughly at the end of April, 2012 ; diff --git a/src/crypto/siphash.cpp b/src/crypto/siphash.cpp index 2e0106b165..2e90c393e1 100644 --- a/src/crypto/siphash.cpp +++ b/src/crypto/siphash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/crypto/siphash.h b/src/crypto/siphash.h index 6b38950f8e..b573526932 100644 --- a/src/crypto/siphash.h +++ b/src/crypto/siphash.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/cuckoocache.h b/src/cuckoocache.h index 2daf676c4a..1166466771 100644 --- a/src/cuckoocache.h +++ b/src/cuckoocache.h @@ -225,7 +225,7 @@ private: * [0, 1) and simply multiply it by the size. Then we just shift the result down by * 32-bits to get our bucket number. The result has non-uniformity the same as a * mod, but it is much faster to compute. More about this technique can be found at - * http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ . + * https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ . * * The resulting non-uniformity is also more equally distributed which would be * advantageous for something like linear probing, though it shouldn't matter diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 215b033708..33e4b366a1 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 8d2dcd0279..4543f098a1 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -40,7 +40,6 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const "-salvagewallet", "-spendzeroconfchange", "-txconfirmtarget=<n>", - "-upgradewallet", "-wallet=<path>", "-walletbroadcast", "-walletdir=<dir>", diff --git a/src/flatfile.cpp b/src/flatfile.cpp index 8a8f7b681c..11cf357f3d 100644 --- a/src/flatfile.cpp +++ b/src/flatfile.cpp @@ -92,6 +92,7 @@ bool FlatFileSeq::Flush(const FlatFilePos& pos, bool finalize) fclose(file); return error("%s: failed to commit file %d", __func__, pos.nFile); } + DirectoryCommit(m_dir); fclose(file); return true; diff --git a/src/fs.cpp b/src/fs.cpp index eef9c81de9..4f20ca4d28 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -31,6 +31,12 @@ FILE *fopen(const fs::path& p, const char *mode) #endif } +fs::path AbsPathJoin(const fs::path& base, const fs::path& path) +{ + assert(base.is_absolute()); + return fs::absolute(path, base); +} + #ifndef WIN32 static std::string GetErrorReason() @@ -21,6 +21,17 @@ namespace fs = boost::filesystem; namespace fsbridge { FILE *fopen(const fs::path& p, const char *mode); + /** + * Helper function for joining two paths + * + * @param[in] base Base path + * @param[in] path Path to combine with base + * @returns path unchanged if it is an absolute path, otherwise returns base joined with path. Returns base unchanged if path is empty. + * @pre Base path must be absolute + * @post Returned path will always be absolute + */ + fs::path AbsPathJoin(const fs::path& base, const fs::path& path); + class FileLock { public: diff --git a/src/hash.cpp b/src/hash.cpp index 83b90ae063..cc46043c2b 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2018 The Bitcoin Core developers +// Copyright (c) 2013-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,6 +6,7 @@ #include <crypto/common.h> #include <crypto/hmac_sha512.h> +#include <string> inline uint32_t ROTL32(uint32_t x, int8_t r) { @@ -14,7 +15,7 @@ inline uint32_t ROTL32(uint32_t x, int8_t r) unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash) { - // The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp + // The following is MurmurHash3 (x86_32), see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp uint32_t h1 = nHashSeed; const uint32_t c1 = 0xcc9e2d51; const uint32_t c2 = 0x1b873593; @@ -84,3 +85,12 @@ uint256 SHA256Uint256(const uint256& input) CSHA256().Write(input.begin(), 32).Finalize(result.begin()); return result; } + +CHashWriter TaggedHash(const std::string& tag) +{ + CHashWriter writer(SER_GETHASH, 0); + uint256 taghash; + CSHA256().Write((const unsigned char*)tag.data(), tag.size()).Finalize(taghash.begin()); + writer << taghash << taghash; + return writer; +} diff --git a/src/hash.h b/src/hash.h index c16bbb48ce..1456a899d8 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +15,7 @@ #include <uint256.h> #include <version.h> +#include <string> #include <vector> typedef uint256 ChainCode; @@ -196,10 +197,18 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL } /** Single-SHA256 a 32-byte input (represented as uint256). */ -NODISCARD uint256 SHA256Uint256(const uint256& input); +[[nodiscard]] uint256 SHA256Uint256(const uint256& input); unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash); void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); +/** Return a CHashWriter primed for tagged hashes (as specified in BIP 340). + * + * The returned object will have SHA256(tag) written to it twice (= 64 bytes). + * A tagged hash can be computed by feeding the message into this object, and + * then calling CHashWriter::GetSHA256(). + */ +CHashWriter TaggedHash(const std::string& tag); + #endif // BITCOIN_HASH_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index f1b9997371..cb8b220895 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -68,6 +68,8 @@ private: static std::string strRPCUserColonPass; /* Stored RPC timer interface (for unregistration) */ static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface; +/* List of -rpcauth values */ +static std::vector<std::vector<std::string>> g_rpcauth; /* RPC Auth Whitelist */ static std::map<std::string, std::set<std::string>> g_rpc_whitelist; static bool g_rpc_whitelist_default = false; @@ -99,15 +101,7 @@ static bool multiUserAuthorized(std::string strUserPass) std::string strUser = strUserPass.substr(0, strUserPass.find(':')); std::string strPass = strUserPass.substr(strUserPass.find(':') + 1); - for (const std::string& strRPCAuth : gArgs.GetArgs("-rpcauth")) { - //Search for multi-user login/pass "rpcauth" from config - std::vector<std::string> vFields; - boost::split(vFields, strRPCAuth, boost::is_any_of(":$")); - if (vFields.size() != 3) { - //Incorrect formatting in config file - continue; - } - + for (const auto& vFields : g_rpcauth) { std::string strName = vFields[0]; if (!TimingResistantEqual(strName, strUser)) { continue; @@ -259,6 +253,16 @@ static bool InitRPCAuthentication() if (gArgs.GetArg("-rpcauth","") != "") { LogPrintf("Using rpcauth authentication.\n"); + for (const std::string& rpcauth : gArgs.GetArgs("-rpcauth")) { + std::vector<std::string> fields; + boost::split(fields, rpcauth, boost::is_any_of(":$")); + if (fields.size() == 3) { + g_rpcauth.push_back(fields); + } else { + LogPrintf("Invalid -rpcauth argument.\n"); + return false; + } + } } g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault", gArgs.IsArgSet("-rpcwhitelist")); diff --git a/src/httprpc.h b/src/httprpc.h index a6a38fc95a..97af6f7bb1 100644 --- a/src/httprpc.h +++ b/src/httprpc.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 1e5ea2de83..0a8e58ab67 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -33,13 +33,6 @@ #include <support/events.h> -#ifdef EVENT__HAVE_NETINET_IN_H -#include <netinet/in.h> -#ifdef _XOPEN_SOURCE_EXTENDED -#include <arpa/inet.h> -#endif -#endif - /** Maximum size of http request (request line + headers) */ static const size_t MAX_HEADERS_SIZE = 8192; diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index 65a5f03a8e..4f61bbeabd 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -51,7 +51,6 @@ struct DBVal { struct DBHeightKey { int height; - DBHeightKey() : height(0) {} explicit DBHeightKey(int height_in) : height(height_in) {} template<typename Stream> diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h index 317f8c0e40..221ac02c9e 100644 --- a/src/index/blockfilterindex.h +++ b/src/index/blockfilterindex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,15 +9,11 @@ #include <chain.h> #include <flatfile.h> #include <index/base.h> +#include <util/hasher.h> /** Interval between compact filter checkpoints. See BIP 157. */ static constexpr int CFCHECKPT_INTERVAL = 1000; -struct FilterHeaderHasher -{ - size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } -}; - /** * BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of * blocks by height. An index is constructed for each supported filter type with its own database diff --git a/src/index/disktxpos.h b/src/index/disktxpos.h index 69696b0ec5..3166053226 100644 --- a/src/index/disktxpos.h +++ b/src/index/disktxpos.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 462ac5962f..6398b7edc8 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/init.cpp b/src/init.cpp index c517b04d68..64bbf8988d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -26,6 +26,7 @@ #include <interfaces/chain.h> #include <interfaces/node.h> #include <key.h> +#include <mapport.h> #include <miner.h> #include <net.h> #include <net_permissions.h> @@ -37,6 +38,7 @@ #include <policy/fees.h> #include <policy/policy.h> #include <policy/settings.h> +#include <protocol.h> #include <rpc/blockchain.h> #include <rpc/register.h> #include <rpc/server.h> @@ -84,7 +86,6 @@ #include <zmq/zmqrpc.h> #endif -static bool fFeeEstimatesInitialized = false; static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_REST_ENABLE = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; @@ -98,8 +99,6 @@ static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; #define MIN_CORE_FILEDESCRIPTORS 150 #endif -static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; - static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map"; /** @@ -112,7 +111,7 @@ static fs::path GetPidFile(const ArgsManager& args) return AbsPathForConfigVal(fs::path(args.GetArg("-pid", BITCOIN_PID_FILENAME))); } -NODISCARD static bool CreatePidFile(const ArgsManager& args) +[[nodiscard]] static bool CreatePidFile(const ArgsManager& args) { fsbridge::ofstream file{GetPidFile(args)}; if (file) { @@ -202,7 +201,7 @@ void Shutdown(NodeContext& node) // using the other before destroying them. if (node.peerman) UnregisterValidationInterface(node.peerman.get()); // Follow the lock order requirements: - // * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling GetExtraOutboundCount + // * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling GetExtraFullOutboundCount // which locks cs_vNodes. // * ProcessMessage locks cs_main and g_cs_orphans before indirectly calling ForEachNode which // locks cs_vNodes. @@ -224,6 +223,7 @@ void Shutdown(NodeContext& node) if (g_load_block.joinable()) g_load_block.join(); threadGroup.interrupt_all(); threadGroup.join_all(); + StopScriptCheckWorkerThreads(); // After the threads that potentially access these pointers have been stopped, // destruct and reset all to nullptr. @@ -235,17 +235,8 @@ void Shutdown(NodeContext& node) DumpMempool(*node.mempool); } - if (fFeeEstimatesInitialized) - { - ::feeEstimator.FlushUnconfirmed(); - fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; - CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION); - if (!est_fileout.IsNull()) - ::feeEstimator.Write(est_fileout); - else - LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string()); - fFeeEstimatesInitialized = false; - } + // Drop transactions we were still watching, and record fee estimations. + if (node.fee_estimator) node.fee_estimator->Flush(); // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing if (node.chainman) { @@ -303,6 +294,7 @@ void Shutdown(NodeContext& node) globalVerifyHandle.reset(); ECC_Stop(); node.mempool.reset(); + node.fee_estimator.reset(); node.chainman = nullptr; node.scheduler.reset(); @@ -380,10 +372,10 @@ void SetupServerArgs(NodeContext& node) const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); const auto signetBaseParams = CreateBaseChainParams(CBaseChainParams::SIGNET); const auto regtestBaseParams = CreateBaseChainParams(CBaseChainParams::REGTEST); - const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN); - const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET); - const auto signetChainParams = CreateChainParams(CBaseChainParams::SIGNET); - const auto regtestChainParams = CreateChainParams(CBaseChainParams::REGTEST); + const auto defaultChainParams = CreateChainParams(argsman, CBaseChainParams::MAIN); + const auto testnetChainParams = CreateChainParams(argsman, CBaseChainParams::TESTNET); + const auto signetChainParams = CreateChainParams(argsman, CBaseChainParams::SIGNET); + const auto regtestChainParams = CreateChainParams(argsman, CBaseChainParams::REGTEST); // Hidden Options std::vector<std::string> hidden_args = { @@ -441,7 +433,7 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-addnode=<ip>", "Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info). This option can be specified multiple times to add multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-bind=<addr>", "Bind to given address and always listen on it. Use [host]:port notation for IPv6", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); + argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), signetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -456,11 +448,11 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'download' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks. Warning: if it is used with ipv4 or ipv6 but not onion and the -onion or -proxy option is set, then outbound onion connections will still be made; use -noonion or -onion=0 to disable outbound onion connections in this case.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port> (default: %u, testnet: %u signet: %u, regtest: %u)", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); + argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, signet: %u, regtest: %u) are unlikely to get incoming connections.", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-proxy=<ip:port>", "Connect through SOCKS5 proxy, set -noproxy to disable (default: disabled)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-proxyrandomize", strprintf("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)", DEFAULT_PROXYRANDOMIZE), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -478,6 +470,11 @@ void SetupServerArgs(NodeContext& node) #else hidden_args.emplace_back("-upnp"); #endif +#ifdef USE_NATPMP + argsman.AddArg("-natpmp", strprintf("Use NAT-PMP to map the listening port (default: %s)", DEFAULT_NATPMP ? "1 when listening and no -proxy" : "0"), ArgsManager::ALLOW_BOOL, OptionsCategory::CONNECTION); +#else + hidden_args.emplace_back("-natpmp"); +#endif // USE_NATPMP argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers connecting to it. " "Use [host]:port notation for IPv6. Allowed permissions: " + Join(NET_PERMISSIONS_DOC, ", ") + ". " "Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); @@ -518,7 +515,6 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); @@ -823,10 +819,13 @@ void InitParameterInteraction(ArgsManager& args) // to protect privacy, do not listen by default if a default proxy server is specified if (args.SoftSetBoolArg("-listen", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); - // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1 + // to protect privacy, do not map ports when a proxy is set. The user may still specify -listen=1 // to listen locally, so don't rely on this happening through -listen below. if (args.SoftSetBoolArg("-upnp", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); + if (args.SoftSetBoolArg("-natpmp", false)) { + LogPrintf("%s: parameter interaction: -proxy set -> setting -natpmp=0\n", __func__); + } // to protect privacy, do not discover addresses by default if (args.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__); @@ -836,6 +835,9 @@ void InitParameterInteraction(ArgsManager& args) // do not map ports or try to retrieve public IP when not listening (pointless) if (args.SoftSetBoolArg("-upnp", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); + if (args.SoftSetBoolArg("-natpmp", false)) { + LogPrintf("%s: parameter interaction: -listen=0 -> setting -natpmp=0\n", __func__); + } if (args.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); if (args.SoftSetBoolArg("-listenonion", false)) @@ -913,7 +915,7 @@ std::set<BlockFilterType> g_enabled_filter_types; std::terminate(); }; -bool AppInitBasicSetup(ArgsManager& args) +bool AppInitBasicSetup(const ArgsManager& args) { // ********************************************************* Step 1: setup #ifdef _MSC_VER @@ -927,6 +929,9 @@ bool AppInitBasicSetup(ArgsManager& args) // Enable heap terminate-on-corruption HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0); #endif + if (!InitShutdownState()) { + return InitError(Untranslated("Initializing wait-for-shutdown state failed.")); + } if (!SetupNetworking()) { return InitError(Untranslated("Initializing networking failed.")); @@ -966,6 +971,9 @@ bool AppInitParameterInteraction(const ArgsManager& args) // specified in default section of config file, but not overridden // on the command line or in this network's section of the config file. std::string network = args.GetChainName(); + if (network == CBaseChainParams::SIGNET) { + LogPrintf("Signet derived magic (message start): %s\n", HexStr(chainparams.MessageStart())); + } bilingual_str errors; for (const auto& arg : args.GetUnsuitableSectionOnlyArgs()) { errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section.") + Untranslated("\n"), arg, network, network); @@ -1035,7 +1043,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) // Trim requested connection counts, to fit into system limitations // <int> in std::min<int>(...) to work around FreeBSD compilation issue described in #2695 - nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS); + nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS + nBind); #ifdef USE_POLL int fd_max = nFD; #else @@ -1141,7 +1149,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) if (!ParseMoney(args.GetArg("-minrelaytxfee", ""), n)) { return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", ""))); } - // High fee check is done afterward in CWallet::CreateWalletFromFile() + // High fee check is done afterward in CWallet::Create() ::minRelayTxFee = CFeeRate(n); } else if (incrementalRelayFee > ::minRelayTxFee) { // Allow only setting incrementalRelayFee to control both @@ -1327,9 +1335,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA LogPrintf("Script verification uses %d additional threads\n", script_threads); if (script_threads >= 1) { g_parallel_script_checks = true; - for (int i = 0; i < script_threads; ++i) { - threadGroup.create_thread([i]() { return ThreadScriptCheck(i); }); - } + StartScriptCheckWorkerThreads(script_threads); } assert(!node.scheduler); @@ -1380,27 +1386,31 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA // is not yet setup and may end up being set up twice if we // need to reindex later. + fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN); + fDiscover = args.GetBoolArg("-discover", true); + const bool ignores_incoming_txs{args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)}; + assert(!node.banman); node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); assert(!node.connman); node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), args.GetBoolArg("-networkactive", true)); - // Make mempool generally available in the node context. For example the connection manager, wallet, or RPC threads, - // which are all started after this, may use it from the node context. + assert(!node.fee_estimator); + // Don't initialize fee estimation with old data if we don't relay transactions, + // as they would never get updated. + if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(); + assert(!node.mempool); - node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator); - if (node.mempool) { - int ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); - if (ratio != 0) { - node.mempool->setSanityCheck(1.0 / ratio); - } - } + int check_ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio); assert(!node.chainman); node.chainman = &g_chainman; ChainstateManager& chainman = *Assert(node.chainman); - node.peerman.reset(new PeerManager(chainparams, *node.connman, node.banman.get(), *node.scheduler, chainman, *node.mempool)); + assert(!node.peerman); + node.peerman = PeerManager::make(chainparams, *node.connman, node.banman.get(), + *node.scheduler, chainman, *node.mempool, ignores_incoming_txs); RegisterValidationInterface(node.peerman.get()); // sanitize comments per BIP-0014, format user agent and check total size @@ -1476,11 +1486,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } } - // see Step 2: parameter interactions for more information about these - fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN); - fDiscover = args.GetBoolArg("-discover", true); - g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); - for (const std::string& strAddr : args.GetArgs("-externalip")) { CService addrLocal; if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) @@ -1521,12 +1526,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA RegisterValidationInterface(g_zmq_notification_interface); } #endif - uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set - uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME; - - if (args.IsArgSet("-maxuploadtarget")) { - nMaxOutboundLimit = args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET) * 1024 * 1024; - } // ********************************************************* Step 7: load block chain @@ -1788,13 +1787,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA return false; } - fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; - CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION); - // Allowed to fail as this file IS missing on first startup. - if (!est_filein.IsNull()) - ::feeEstimator.Read(est_filein); - fFeeEstimatesInitialized = true; - // ********************************************************* Step 8: start indexers if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { g_txindex = MakeUnique<TxIndex>(nTxIndexCache, false, fReindex); @@ -1913,16 +1905,12 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } } LogPrintf("nBestHeight = %d\n", chain_active_height); - - if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) - StartTorControl(); + if (node.peerman) node.peerman->SetBestHeight(chain_active_height); Discover(); - // Map ports with UPnP - if (args.GetBoolArg("-upnp", DEFAULT_UPNP)) { - StartMapPort(); - } + // Map ports with UPnP or NAT-PMP. + StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP)); CConnman::Options connOptions; connOptions.nLocalServices = nLocalServices; @@ -1931,7 +1919,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA connOptions.m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, connOptions.nMaxConnections-connOptions.m_max_outbound_full_relay); connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS; connOptions.nMaxFeeler = MAX_FEELER_CONNECTIONS; - connOptions.nBestHeight = chain_active_height; connOptions.uiInterface = &uiInterface; connOptions.m_banman = node.banman.get(); connOptions.m_msgproc = node.peerman.get(); @@ -1939,17 +1926,42 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA connOptions.nReceiveFloodSize = 1000 * args.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); connOptions.m_added_nodes = args.GetArgs("-addnode"); - connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe; - connOptions.nMaxOutboundLimit = nMaxOutboundLimit; + connOptions.nMaxOutboundLimit = 1024 * 1024 * args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET); connOptions.m_peer_connect_timeout = peer_connect_timeout; - for (const std::string& strBind : args.GetArgs("-bind")) { - CService addrBind; - if (!Lookup(strBind, addrBind, GetListenPort(), false)) { - return InitError(ResolveErrMsg("bind", strBind)); + for (const std::string& bind_arg : args.GetArgs("-bind")) { + CService bind_addr; + const size_t index = bind_arg.rfind('='); + if (index == std::string::npos) { + if (Lookup(bind_arg, bind_addr, GetListenPort(), false)) { + connOptions.vBinds.push_back(bind_addr); + continue; + } + } else { + const std::string network_type = bind_arg.substr(index + 1); + if (network_type == "onion") { + const std::string truncated_bind_arg = bind_arg.substr(0, index); + if (Lookup(truncated_bind_arg, bind_addr, BaseParams().OnionServiceTargetPort(), false)) { + connOptions.onion_binds.push_back(bind_addr); + continue; + } + } + } + return InitError(ResolveErrMsg("bind", bind_arg)); + } + + if (connOptions.onion_binds.empty()) { + connOptions.onion_binds.push_back(DefaultOnionServiceTarget()); + } + + if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) { + const auto bind_addr = connOptions.onion_binds.front(); + if (connOptions.onion_binds.size() > 1) { + InitWarning(strprintf(_("More than one onion bind address is provided. Using %s for the automatically created Tor onion service."), bind_addr.ToStringIPPort())); } - connOptions.vBinds.push_back(addrBind); + StartTorControl(bind_addr); } + for (const std::string& strBind : args.GetArgs("-whitebind")) { NetWhitebindPermissions whitebind; bilingual_str error; diff --git a/src/init.h b/src/init.h index 679e875da1..c04d966d06 100644 --- a/src/init.h +++ b/src/init.h @@ -33,7 +33,7 @@ void InitParameterInteraction(ArgsManager& args); * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read. */ -bool AppInitBasicSetup(ArgsManager& args); +bool AppInitBasicSetup(const ArgsManager& args); /** * Initialization: parameter interaction. * @note This can be done before daemonization. Do not call Shutdown() if this function fails. diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 85d09be0f3..1a49518d69 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -44,6 +44,10 @@ public: FoundBlock& time(int64_t& time) { m_time = &time; return *this; } FoundBlock& maxTime(int64_t& max_time) { m_max_time = &max_time; return *this; } FoundBlock& mtpTime(int64_t& mtp_time) { m_mtp_time = &mtp_time; return *this; } + //! Return whether block is in the active (most-work) chain. + FoundBlock& inActiveChain(bool& in_active_chain) { m_in_active_chain = &in_active_chain; return *this; } + //! Return next block in the active chain if current block is in the active chain. + FoundBlock& nextBlock(const FoundBlock& next_block) { m_next_block = &next_block; return *this; } //! Read block data from disk. If the block exists but doesn't have data //! (for example due to pruning), the CBlock variable will be set to null. FoundBlock& data(CBlock& data) { m_data = &data; return *this; } @@ -53,6 +57,8 @@ public: int64_t* m_time = nullptr; int64_t* m_max_time = nullptr; int64_t* m_mtp_time = nullptr; + bool* m_in_active_chain = nullptr; + const FoundBlock* m_next_block = nullptr; CBlock* m_data = nullptr; }; @@ -77,9 +83,9 @@ public: //! wallet cache it, fee estimation being driven by node mempool, wallet //! should be the consumer. //! -//! * The `guessVerificationProgress`, `getBlockHeight`, `getBlockHash`, etc -//! methods can go away if rescan logic is moved on the node side, and wallet -//! only register rescan request. +//! * `guessVerificationProgress` and similar methods can go away if rescan +//! logic moves out of the wallet, and the wallet just requests scans from the +//! node (https://github.com/bitcoin/bitcoin/issues/11756) class Chain { public: @@ -90,11 +96,6 @@ public: //! 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 hash. Height must be valid or this function will abort. virtual uint256 getBlockHash(int height) = 0; @@ -102,13 +103,6 @@ public: //! 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 and height equal or greater than the - //! given height, or nullopt if there is no block with a high enough - //! timestamp and height. 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> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) = 0; - //! Get locator for the current chain tip. virtual CBlockLocator getTipLocator() = 0; @@ -130,11 +124,6 @@ public: //! information. virtual bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block={}) = 0; - //! Find next block if block is part of current chain. Also flag if - //! there was a reorg and the specified block hash is no longer in the - //! current chain, and optionally return block information. - virtual bool findNextBlock(const uint256& block_hash, int block_height, const FoundBlock& next={}, bool* reorg=nullptr) = 0; - //! Find ancestor of block at specified height and optionally return //! ancestor information. virtual bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out={}) = 0; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp deleted file mode 100644 index 2c5f8627e6..0000000000 --- a/src/interfaces/node.cpp +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include <interfaces/node.h> - -#include <addrdb.h> -#include <banman.h> -#include <chain.h> -#include <chainparams.h> -#include <init.h> -#include <interfaces/chain.h> -#include <interfaces/handler.h> -#include <interfaces/wallet.h> -#include <net.h> -#include <net_processing.h> -#include <netaddress.h> -#include <netbase.h> -#include <node/context.h> -#include <node/ui_interface.h> -#include <policy/feerate.h> -#include <policy/fees.h> -#include <policy/settings.h> -#include <primitives/block.h> -#include <rpc/server.h> -#include <shutdown.h> -#include <support/allocators/secure.h> -#include <sync.h> -#include <txmempool.h> -#include <util/check.h> -#include <util/ref.h> -#include <util/system.h> -#include <util/translation.h> -#include <validation.h> -#include <warnings.h> - -#if defined(HAVE_CONFIG_H) -#include <config/bitcoin-config.h> -#endif - -#include <univalue.h> - -#include <boost/signals2/signal.hpp> - -namespace interfaces { -namespace { - -class NodeImpl : public Node -{ -public: - NodeImpl(NodeContext* context) { setContext(context); } - void initLogging() override { InitLogging(*Assert(m_context->args)); } - void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); } - bilingual_str getWarnings() override { return GetWarnings(true); } - uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); } - bool baseInitialize() override - { - return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() && - AppInitLockDataDirectory() && AppInitInterfaces(*m_context); - } - bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override - { - return AppInitMain(m_context_ref, *m_context, tip_info); - } - void appShutdown() override - { - Interrupt(*m_context); - Shutdown(*m_context); - } - void startShutdown() override - { - StartShutdown(); - // Stop RPC for clean shutdown if any of waitfor* commands is executed. - if (gArgs.GetBoolArg("-server", false)) { - InterruptRPC(); - StopRPC(); - } - } - bool shutdownRequested() override { return ShutdownRequested(); } - void mapPort(bool use_upnp) override - { - if (use_upnp) { - StartMapPort(); - } else { - InterruptMapPort(); - StopMapPort(); - } - } - bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); } - size_t getNodeCount(CConnman::NumConnections flags) override - { - return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0; - } - bool getNodesStats(NodesStats& stats) override - { - stats.clear(); - - if (m_context->connman) { - std::vector<CNodeStats> stats_temp; - m_context->connman->GetNodeStats(stats_temp); - - stats.reserve(stats_temp.size()); - for (auto& node_stats_temp : stats_temp) { - stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats()); - } - - // Try to retrieve the CNodeStateStats for each node. - TRY_LOCK(::cs_main, lockMain); - if (lockMain) { - for (auto& node_stats : stats) { - std::get<1>(node_stats) = - GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats)); - } - } - return true; - } - return false; - } - bool getBanned(banmap_t& banmap) override - { - if (m_context->banman) { - m_context->banman->GetBanned(banmap); - return true; - } - return false; - } - bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override - { - if (m_context->banman) { - m_context->banman->Ban(net_addr, ban_time_offset); - return true; - } - return false; - } - bool unban(const CSubNet& ip) override - { - if (m_context->banman) { - m_context->banman->Unban(ip); - return true; - } - return false; - } - bool disconnectByAddress(const CNetAddr& net_addr) override - { - if (m_context->connman) { - return m_context->connman->DisconnectNode(net_addr); - } - return false; - } - bool disconnectById(NodeId id) override - { - if (m_context->connman) { - return m_context->connman->DisconnectNode(id); - } - return false; - } - int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; } - int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; } - size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; } - size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; } - bool getHeaderTip(int& height, int64_t& block_time) override - { - LOCK(::cs_main); - if (::pindexBestHeader) { - height = ::pindexBestHeader->nHeight; - block_time = ::pindexBestHeader->GetBlockTime(); - return true; - } - return false; - } - int getNumBlocks() override - { - LOCK(::cs_main); - return ::ChainActive().Height(); - } - uint256 getBestBlockHash() override - { - const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip()); - return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash(); - } - int64_t getLastBlockTime() override - { - LOCK(::cs_main); - if (::ChainActive().Tip()) { - return ::ChainActive().Tip()->GetBlockTime(); - } - return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network - } - double getVerificationProgress() override - { - const CBlockIndex* tip; - { - LOCK(::cs_main); - tip = ::ChainActive().Tip(); - } - return GuessVerificationProgress(Params().TxData(), tip); - } - bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); } - bool getReindex() override { return ::fReindex; } - bool getImporting() override { return ::fImporting; } - void setNetworkActive(bool active) override - { - if (m_context->connman) { - m_context->connman->SetNetworkActive(active); - } - } - bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); } - CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override - { - FeeCalculation fee_calc; - CFeeRate result = ::feeEstimator.estimateSmartFee(num_blocks, &fee_calc, conservative); - if (returned_target) { - *returned_target = fee_calc.returnedTarget; - } - return result; - } - CFeeRate getDustRelayFee() override { return ::dustRelayFee; } - UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override - { - JSONRPCRequest req(m_context_ref); - req.params = params; - req.strMethod = command; - req.URI = uri; - return ::tableRPC.execute(req); - } - std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); } - void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); } - void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); } - bool getUnspentOutput(const COutPoint& output, Coin& coin) override - { - LOCK(::cs_main); - return ::ChainstateActive().CoinsTip().GetCoin(output, coin); - } - WalletClient& walletClient() override - { - return *Assert(m_context->wallet_client); - } - std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override - { - return MakeHandler(::uiInterface.InitMessage_connect(fn)); - } - std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override - { - return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn)); - } - std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override - { - return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn)); - } - std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override - { - return MakeHandler(::uiInterface.ShowProgress_connect(fn)); - } - std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override - { - return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn)); - } - std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override - { - return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn)); - } - std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override - { - return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn)); - } - std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override - { - return MakeHandler(::uiInterface.BannedListChanged_connect(fn)); - } - std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override - { - return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { - fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()}, - GuessVerificationProgress(Params().TxData(), block)); - })); - } - std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override - { - return MakeHandler( - ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { - fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()}, - /* verification progress is unused when a header was received */ 0); - })); - } - NodeContext* context() override { return m_context; } - void setContext(NodeContext* context) override - { - m_context = context; - if (context) { - m_context_ref.Set(*context); - } else { - m_context_ref.Clear(); - } - } - NodeContext* m_context{nullptr}; - util::Ref m_context_ref; -}; - -} // namespace - -std::unique_ptr<Node> MakeNode(NodeContext* context) { return MakeUnique<NodeImpl>(context); } - -} // namespace interfaces diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 5079be038e..15f7ef6256 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -82,7 +82,7 @@ public: virtual bool shutdownRequested() = 0; //! Map port. - virtual void mapPort(bool use_upnp) = 0; + virtual void mapPort(bool use_upnp, bool use_natpmp) = 0; //! Get proxy. virtual bool getProxy(Network net, proxyType& proxy_info) = 0; @@ -151,9 +151,6 @@ public: //! Get network active. virtual bool getNetworkActive() = 0; - //! Estimate smart fee. - virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) = 0; - //! Get dust relay fee. virtual CFeeRate getDustRelayFee() = 0; diff --git a/src/key.cpp b/src/key.cpp index 868a8b9b0e..1e59b301cb 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,7 +18,7 @@ static secp256k1_context* secp256k1_context_sign = nullptr; /** * This parses a format loosely based on a DER encoding of the ECPrivateKey type from - * section C.4 of SEC 1 <http://www.secg.org/sec1-v2.pdf>, with the following caveats: + * section C.4 of SEC 1 <https://www.secg.org/sec1-v2.pdf>, with the following caveats: * * * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is not * required to be encoded as one octet if it is less than 256, as DER would require. @@ -80,7 +80,7 @@ int ec_seckey_import_der(const secp256k1_context* ctx, unsigned char *out32, con /** * This serializes to a DER encoding of the ECPrivateKey type from section C.4 of SEC 1 - * <http://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are + * <https://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are * included. * * seckey must point to an output buffer of length at least CKey::SIZE bytes. diff --git a/src/key_io.cpp b/src/key_io.cpp index d2f5be93f5..e27673fd16 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -8,16 +8,15 @@ #include <bech32.h> #include <util/strencodings.h> -#include <boost/variant/apply_visitor.hpp> -#include <boost/variant/static_visitor.hpp> - +#include <algorithm> #include <assert.h> #include <string.h> -#include <algorithm> -namespace -{ -class DestinationEncoder : public boost::static_visitor<std::string> +/// Maximum witness length for Bech32 addresses. +static constexpr std::size_t BECH32_WITNESS_PROG_MAX_LEN = 40; + +namespace { +class DestinationEncoder { private: const CChainParams& m_params; @@ -69,10 +68,11 @@ public: std::string operator()(const CNoDestination& no) const { return {}; } }; -CTxDestination DecodeDestination(const std::string& str, const CChainParams& params) +CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str) { std::vector<unsigned char> data; uint160 hash; + error_str = ""; if (DecodeBase58Check(str, data, 21)) { // base58-encoded Bitcoin addresses. // Public-key-hash-addresses have version 0 (or 111 testnet). @@ -89,10 +89,21 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin()); return ScriptHash(hash); } + + // Set potential error message. + // This message may be changed if the address can also be interpreted as a Bech32 address. + error_str = "Invalid prefix for Base58-encoded address"; } data.clear(); auto bech = bech32::Decode(str); - if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) { + if (bech.second.size() > 0) { + error_str = ""; + + if (bech.first != params.Bech32HRP()) { + error_str = "Invalid prefix for Bech32 address"; + return CNoDestination(); + } + // Bech32 decoding int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16) // The rest of the symbols are converted witness program bytes. @@ -113,11 +124,21 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par return scriptid; } } + + error_str = "Invalid Bech32 v0 address data size"; return CNoDestination(); } - if (version > 16 || data.size() < 2 || data.size() > 40) { + + if (version > 16) { + error_str = "Invalid Bech32 address witness version"; return CNoDestination(); } + + if (data.size() < 2 || data.size() > BECH32_WITNESS_PROG_MAX_LEN) { + error_str = "Invalid Bech32 address data size"; + return CNoDestination(); + } + WitnessUnknown unk; unk.version = version; std::copy(data.begin(), data.end(), unk.program); @@ -125,6 +146,10 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par return unk; } } + + // Set error message if address can't be interpreted as Base58 or Bech32. + if (error_str.empty()) error_str = "Invalid address format"; + return CNoDestination(); } } // namespace @@ -209,17 +234,24 @@ std::string EncodeExtKey(const CExtKey& key) std::string EncodeDestination(const CTxDestination& dest) { - return boost::apply_visitor(DestinationEncoder(Params()), dest); + return std::visit(DestinationEncoder(Params()), dest); +} + +CTxDestination DecodeDestination(const std::string& str, std::string& error_msg) +{ + return DecodeDestination(str, Params(), error_msg); } CTxDestination DecodeDestination(const std::string& str) { - return DecodeDestination(str, Params()); + std::string error_msg; + return DecodeDestination(str, error_msg); } bool IsValidDestinationString(const std::string& str, const CChainParams& params) { - return IsValidDestination(DecodeDestination(str, params)); + std::string error_msg; + return IsValidDestination(DecodeDestination(str, params, error_msg)); } bool IsValidDestinationString(const std::string& str) diff --git a/src/key_io.h b/src/key_io.h index d80c08f49c..bd81f7847e 100644 --- a/src/key_io.h +++ b/src/key_io.h @@ -23,6 +23,7 @@ std::string EncodeExtPubKey(const CExtPubKey& extpubkey); std::string EncodeDestination(const CTxDestination& dest); CTxDestination DecodeDestination(const std::string& str); +CTxDestination DecodeDestination(const std::string& str, std::string& error_msg); bool IsValidDestinationString(const std::string& str); bool IsValidDestinationString(const std::string& str, const CChainParams& params); diff --git a/src/limitedmap.h b/src/limitedmap.h deleted file mode 100644 index 7d66964e36..0000000000 --- a/src/limitedmap.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2012-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_LIMITEDMAP_H -#define BITCOIN_LIMITEDMAP_H - -#include <assert.h> -#include <map> - -/** STL-like map container that only keeps the N elements with the highest value. */ -template <typename K, typename V> -class limitedmap -{ -public: - typedef K key_type; - typedef V mapped_type; - typedef std::pair<const key_type, mapped_type> value_type; - typedef typename std::map<K, V>::const_iterator const_iterator; - typedef typename std::map<K, V>::size_type size_type; - -protected: - std::map<K, V> map; - typedef typename std::map<K, V>::iterator iterator; - std::multimap<V, iterator> rmap; - typedef typename std::multimap<V, iterator>::iterator rmap_iterator; - size_type nMaxSize; - -public: - explicit limitedmap(size_type nMaxSizeIn) - { - assert(nMaxSizeIn > 0); - nMaxSize = nMaxSizeIn; - } - const_iterator begin() const { return map.begin(); } - const_iterator end() const { return map.end(); } - size_type size() const { return map.size(); } - bool empty() const { return map.empty(); } - const_iterator find(const key_type& k) const { return map.find(k); } - size_type count(const key_type& k) const { return map.count(k); } - void insert(const value_type& x) - { - std::pair<iterator, bool> ret = map.insert(x); - if (ret.second) { - if (map.size() > nMaxSize) { - map.erase(rmap.begin()->second); - rmap.erase(rmap.begin()); - } - rmap.insert(make_pair(x.second, ret.first)); - } - } - void erase(const key_type& k) - { - iterator itTarget = map.find(k); - if (itTarget == map.end()) - return; - std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second); - for (rmap_iterator it = itPair.first; it != itPair.second; ++it) - if (it->second == itTarget) { - rmap.erase(it); - map.erase(itTarget); - return; - } - // Shouldn't ever get here - assert(0); - } - void update(const_iterator itIn, const mapped_type& v) - { - // Using map::erase() with empty range instead of map::find() to get a non-const iterator, - // since it is a constant time operation in C++11. For more details, see - // https://stackoverflow.com/questions/765148/how-to-remove-constness-of-const-iterator - iterator itTarget = map.erase(itIn, itIn); - - if (itTarget == map.end()) - return; - std::pair<rmap_iterator, rmap_iterator> itPair = rmap.equal_range(itTarget->second); - for (rmap_iterator it = itPair.first; it != itPair.second; ++it) - if (it->second == itTarget) { - rmap.erase(it); - itTarget->second = v; - rmap.insert(make_pair(v, itTarget)); - return; - } - // Shouldn't ever get here - assert(0); - } - size_type max_size() const { return nMaxSize; } - size_type max_size(size_type s) - { - assert(s > 0); - while (map.size() > s) { - map.erase(rmap.begin()->second); - rmap.erase(rmap.begin()); - } - nMaxSize = s; - return nMaxSize; - } -}; - -#endif // BITCOIN_LIMITEDMAP_H diff --git a/src/logging.cpp b/src/logging.cpp index 35e0754f20..4ddcf1d930 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -174,7 +174,7 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str) return false; } -std::vector<LogCategory> BCLog::Logger::LogCategoriesList() +std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const { std::vector<LogCategory> ret; for (const CLogCategoryDesc& category_desc : LogCategories) { diff --git a/src/logging.h b/src/logging.h index 7e646ef67a..9efecc7c12 100644 --- a/src/logging.h +++ b/src/logging.h @@ -135,9 +135,9 @@ namespace BCLog { bool WillLogCategory(LogFlags category) const; /** Returns a vector of the log categories */ - std::vector<LogCategory> LogCategoriesList(); + std::vector<LogCategory> LogCategoriesList() const; /** Returns a string with the log categories */ - std::string LogCategoriesString() + std::string LogCategoriesString() const { return Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; }); }; diff --git a/src/mapport.cpp b/src/mapport.cpp new file mode 100644 index 0000000000..2df4ce45d2 --- /dev/null +++ b/src/mapport.cpp @@ -0,0 +1,336 @@ +// Copyright (c) 2011-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + +#include <mapport.h> + +#include <clientversion.h> +#include <logging.h> +#include <net.h> +#include <netaddress.h> +#include <netbase.h> +#include <threadinterrupt.h> +#include <util/system.h> + +#ifdef USE_NATPMP +#include <compat.h> +#include <natpmp.h> +#endif // USE_NATPMP + +#ifdef USE_UPNP +#include <miniupnpc/miniupnpc.h> +#include <miniupnpc/upnpcommands.h> +#include <miniupnpc/upnperrors.h> +// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility +// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages. +static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"); +#endif // USE_UPNP + +#include <atomic> +#include <cassert> +#include <chrono> +#include <functional> +#include <string> +#include <thread> + +#if defined(USE_NATPMP) || defined(USE_UPNP) +static CThreadInterrupt g_mapport_interrupt; +static std::thread g_mapport_thread; +static std::atomic_uint g_mapport_enabled_protos{MapPortProtoFlag::NONE}; +static std::atomic<MapPortProtoFlag> g_mapport_current_proto{MapPortProtoFlag::NONE}; + +using namespace std::chrono_literals; +static constexpr auto PORT_MAPPING_REANNOUNCE_PERIOD{20min}; +static constexpr auto PORT_MAPPING_RETRY_PERIOD{5min}; + +#ifdef USE_NATPMP +static uint16_t g_mapport_external_port = 0; +static bool NatpmpInit(natpmp_t* natpmp) +{ + const int r_init = initnatpmp(natpmp, /* detect gateway automatically */ 0, /* forced gateway - NOT APPLIED*/ 0); + if (r_init == 0) return true; + LogPrintf("natpmp: initnatpmp() failed with %d error.\n", r_init); + return false; +} + +static bool NatpmpDiscover(natpmp_t* natpmp, struct in_addr& external_ipv4_addr) +{ + const int r_send = sendpublicaddressrequest(natpmp); + if (r_send == 2 /* OK */) { + int r_read; + natpmpresp_t response; + do { + r_read = readnatpmpresponseorretry(natpmp, &response); + } while (r_read == NATPMP_TRYAGAIN); + + if (r_read == 0) { + external_ipv4_addr = response.pnu.publicaddress.addr; + return true; + } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) { + LogPrintf("natpmp: The gateway does not support NAT-PMP.\n"); + } else { + LogPrintf("natpmp: readnatpmpresponseorretry() for public address failed with %d error.\n", r_read); + } + } else { + LogPrintf("natpmp: sendpublicaddressrequest() failed with %d error.\n", r_send); + } + + return false; +} + +static bool NatpmpMapping(natpmp_t* natpmp, const struct in_addr& external_ipv4_addr, uint16_t private_port, bool& external_ip_discovered) +{ + const uint16_t suggested_external_port = g_mapport_external_port ? g_mapport_external_port : private_port; + const int r_send = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_TCP, private_port, suggested_external_port, 3600 /*seconds*/); + if (r_send == 12 /* OK */) { + int r_read; + natpmpresp_t response; + do { + r_read = readnatpmpresponseorretry(natpmp, &response); + } while (r_read == NATPMP_TRYAGAIN); + + if (r_read == 0) { + auto pm = response.pnu.newportmapping; + if (private_port == pm.privateport && pm.lifetime > 0) { + g_mapport_external_port = pm.mappedpublicport; + const CService external{external_ipv4_addr, pm.mappedpublicport}; + if (!external_ip_discovered && fDiscover) { + AddLocal(external, LOCAL_MAPPED); + external_ip_discovered = true; + } + LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToString()); + return true; + } else { + LogPrintf("natpmp: Port mapping failed.\n"); + } + } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) { + LogPrintf("natpmp: The gateway does not support NAT-PMP.\n"); + } else { + LogPrintf("natpmp: readnatpmpresponseorretry() for port mapping failed with %d error.\n", r_read); + } + } else { + LogPrintf("natpmp: sendnewportmappingrequest() failed with %d error.\n", r_send); + } + + return false; +} + +static bool ProcessNatpmp() +{ + bool ret = false; + natpmp_t natpmp; + struct in_addr external_ipv4_addr; + if (NatpmpInit(&natpmp) && NatpmpDiscover(&natpmp, external_ipv4_addr)) { + bool external_ip_discovered = false; + const uint16_t private_port = GetListenPort(); + do { + ret = NatpmpMapping(&natpmp, external_ipv4_addr, private_port, external_ip_discovered); + } while (ret && g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD)); + g_mapport_interrupt.reset(); + + const int r_send = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, private_port, g_mapport_external_port, /* remove a port mapping */ 0); + g_mapport_external_port = 0; + if (r_send == 12 /* OK */) { + LogPrintf("natpmp: Port mapping removed successfully.\n"); + } else { + LogPrintf("natpmp: sendnewportmappingrequest(0) failed with %d error.\n", r_send); + } + } + + closenatpmp(&natpmp); + return ret; +} +#endif // USE_NATPMP + +#ifdef USE_UPNP +static bool ProcessUpnp() +{ + bool ret = false; + std::string port = strprintf("%u", GetListenPort()); + const char * multicastif = nullptr; + const char * minissdpdpath = nullptr; + struct UPNPDev * devlist = nullptr; + char lanaddr[64]; + + int error = 0; +#if MINIUPNPC_API_VERSION < 14 + devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); +#else + devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error); +#endif + + struct UPNPUrls urls; + struct IGDdatas data; + int r; + + r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); + if (r == 1) + { + if (fDiscover) { + char externalIPAddress[40]; + r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); + if (r != UPNPCOMMAND_SUCCESS) { + LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r); + } else { + if (externalIPAddress[0]) { + CNetAddr resolved; + if (LookupHost(externalIPAddress, resolved, false)) { + LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString()); + AddLocal(resolved, LOCAL_MAPPED); + } + } else { + LogPrintf("UPnP: GetExternalIPAddress failed.\n"); + } + } + } + + std::string strDesc = PACKAGE_NAME " " + FormatFullVersion(); + + do { + r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); + + if (r != UPNPCOMMAND_SUCCESS) { + ret = false; + LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r)); + break; + } else { + ret = true; + LogPrintf("UPnP Port Mapping successful.\n"); + } + } while (g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD)); + g_mapport_interrupt.reset(); + + r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); + LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r); + freeUPNPDevlist(devlist); devlist = nullptr; + FreeUPNPUrls(&urls); + } else { + LogPrintf("No valid UPnP IGDs found\n"); + freeUPNPDevlist(devlist); devlist = nullptr; + if (r != 0) + FreeUPNPUrls(&urls); + } + + return ret; +} +#endif // USE_UPNP + +static void ThreadMapPort() +{ + bool ok; + do { + ok = false; + +#ifdef USE_UPNP + // High priority protocol. + if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) { + g_mapport_current_proto = MapPortProtoFlag::UPNP; + ok = ProcessUpnp(); + if (ok) continue; + } +#endif // USE_UPNP + +#ifdef USE_NATPMP + // Low priority protocol. + if (g_mapport_enabled_protos & MapPortProtoFlag::NAT_PMP) { + g_mapport_current_proto = MapPortProtoFlag::NAT_PMP; + ok = ProcessNatpmp(); + if (ok) continue; + } +#endif // USE_NATPMP + + g_mapport_current_proto = MapPortProtoFlag::NONE; + if (g_mapport_enabled_protos == MapPortProtoFlag::NONE) { + return; + } + + } while (ok || g_mapport_interrupt.sleep_for(PORT_MAPPING_RETRY_PERIOD)); +} + +void StartThreadMapPort() +{ + if (!g_mapport_thread.joinable()) { + assert(!g_mapport_interrupt); + g_mapport_thread = std::thread(std::bind(&TraceThread<void (*)()>, "mapport", &ThreadMapPort)); + } +} + +static void DispatchMapPort() +{ + if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) { + return; + } + + if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos != MapPortProtoFlag::NONE) { + StartThreadMapPort(); + return; + } + + if (g_mapport_current_proto != MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) { + InterruptMapPort(); + StopMapPort(); + return; + } + + if (g_mapport_enabled_protos & g_mapport_current_proto) { + // Enabling another protocol does not cause switching from the currently used one. + return; + } + + assert(g_mapport_thread.joinable()); + assert(!g_mapport_interrupt); + // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadNatpmp() + // to force trying the next protocol in the ThreadMapPort() loop. + g_mapport_interrupt(); +} + +static void MapPortProtoSetEnabled(MapPortProtoFlag proto, bool enabled) +{ + if (enabled) { + g_mapport_enabled_protos |= proto; + } else { + g_mapport_enabled_protos &= ~proto; + } +} + +void StartMapPort(bool use_upnp, bool use_natpmp) +{ + MapPortProtoSetEnabled(MapPortProtoFlag::UPNP, use_upnp); + MapPortProtoSetEnabled(MapPortProtoFlag::NAT_PMP, use_natpmp); + DispatchMapPort(); +} + +void InterruptMapPort() +{ + g_mapport_enabled_protos = MapPortProtoFlag::NONE; + if (g_mapport_thread.joinable()) { + g_mapport_interrupt(); + } +} + +void StopMapPort() +{ + if (g_mapport_thread.joinable()) { + g_mapport_thread.join(); + g_mapport_interrupt.reset(); + } +} + +#else // #if defined(USE_NATPMP) || defined(USE_UPNP) +void StartMapPort(bool use_upnp, bool use_natpmp) +{ + // Intentionally left blank. +} +void InterruptMapPort() +{ + // Intentionally left blank. +} +void StopMapPort() +{ + // Intentionally left blank. +} +#endif // #if defined(USE_NATPMP) || defined(USE_UPNP) diff --git a/src/mapport.h b/src/mapport.h new file mode 100644 index 0000000000..279d65167f --- /dev/null +++ b/src/mapport.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_MAPPORT_H +#define BITCOIN_MAPPORT_H + +#ifdef USE_UPNP +static constexpr bool DEFAULT_UPNP = USE_UPNP; +#else +static constexpr bool DEFAULT_UPNP = false; +#endif // USE_UPNP + +#ifdef USE_NATPMP +static constexpr bool DEFAULT_NATPMP = USE_NATPMP; +#else +static constexpr bool DEFAULT_NATPMP = false; +#endif // USE_NATPMP + +enum MapPortProtoFlag : unsigned int { + NONE = 0x00, + UPNP = 0x01, + NAT_PMP = 0x02, +}; + +void StartMapPort(bool use_upnp, bool use_natpmp); +void InterruptMapPort(); +void StopMapPort(); + +#endif // BITCOIN_MAPPORT_H diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index b571d463c9..3ffe1465da 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -59,7 +59,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve //if we do not have this assert, we can hit a memory access violation when indexing into vTxid assert(vTxid.size() != 0); if (height == 0) { - // hash at height 0 is the txids themself + // hash at height 0 is the txids themselves return vTxid[pos]; } else { // calculate left hash diff --git a/src/merkleblock.h b/src/merkleblock.h index b2d2828784..0e4ed72130 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/miner.cpp b/src/miner.cpp index 41a835f70a..009ae6b13a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -213,7 +213,7 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost // - transaction finality (locktime) // - premature witness (in case segwit transactions are added to mempool before // segwit activation) -bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) +bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) const { for (CTxMemPool::txiter it : package) { if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff)) diff --git a/src/miner.h b/src/miner.h index bb7a30b184..9a2b7063f4 100644 --- a/src/miner.h +++ b/src/miner.h @@ -185,7 +185,7 @@ private: * locktime, premature-witness, serialized size (if necessary) * These checks should always succeed, and they're here * only as an extra check in case of suboptimal node configuration */ - bool TestPackageTransactions(const CTxMemPool::setEntries& package); + bool TestPackageTransactions(const CTxMemPool::setEntries& package) const; /** Return true if given transaction from mapTx has already been evaluated, * or if the transaction's cached data in mapTx is incorrect. */ bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set& mapModifiedTx, CTxMemPool::setEntries& failedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs); diff --git a/src/net.cpp b/src/net.cpp index 3eac2235a5..76bf7effa4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -16,6 +16,7 @@ #include <net_permissions.h> #include <netbase.h> #include <node/ui_interface.h> +#include <optional.h> #include <protocol.h> #include <random.h> #include <scheduler.h> @@ -32,20 +33,19 @@ #include <poll.h> #endif -#ifdef USE_UPNP -#include <miniupnpc/miniupnpc.h> -#include <miniupnpc/upnpcommands.h> -#include <miniupnpc/upnperrors.h> -// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility -// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages. -static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"); -#endif - +#include <algorithm> #include <cstdint> +#include <functional> #include <unordered_map> #include <math.h> +/** Maximum number of block-relay-only anchor connections */ +static constexpr size_t MAX_BLOCK_RELAY_ONLY_ANCHORS = 2; +static_assert (MAX_BLOCK_RELAY_ONLY_ANCHORS <= static_cast<size_t>(MAX_BLOCK_RELAY_ONLY_CONNECTIONS), "MAX_BLOCK_RELAY_ONLY_ANCHORS must not exceed MAX_BLOCK_RELAY_ONLY_CONNECTIONS."); +/** Anchor IP address database file name */ +const char* const ANCHORS_DATABASE_FILENAME = "anchors.dat"; + // How often to dump addresses to peers.dat static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15}; @@ -65,6 +65,9 @@ static constexpr std::chrono::seconds DNSSEEDS_DELAY_FEW_PEERS{11}; static constexpr std::chrono::minutes DNSSEEDS_DELAY_MANY_PEERS{5}; static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" peers +/** The default timeframe for -maxuploadtarget. 1 day. */ +static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24}; + // We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization. #define FEELER_SLEEP_WINDOW 1 @@ -83,6 +86,11 @@ enum BindFlags { BF_NONE = 0, BF_EXPLICIT = (1U << 0), BF_REPORT_ERROR = (1U << 1), + /** + * Do not call AddLocal() for our special addresses, e.g., for incoming + * Tor connections, to prevent gossiping them over the network. + */ + BF_DONT_ADVERTISE = (1U << 2), }; // The set of sockets cannot be modified while waiting @@ -99,7 +107,6 @@ static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256 // bool fDiscover = true; bool fListen = true; -bool g_relay_txes = !DEFAULT_BLOCKSONLY; RecursiveMutex cs_mapLocalHost; std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {}; @@ -342,6 +349,11 @@ CNode* CConnman::FindNode(const CService& addr) return nullptr; } +bool CConnman::AlreadyConnectedToAddress(const CAddress& addr) +{ + return FindNode(static_cast<CNetAddr>(addr)) || FindNode(addr.ToStringIPPort()); +} + bool CConnman::CheckIncomingNonce(uint64_t nonce) { LOCK(cs_vNodes); @@ -461,7 +473,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo NodeId id = GetNewNodeId(); uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); CAddress addr_bind = GetBindAddress(hSocket); - CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type); + CNode* pnode = new CNode(id, nLocalServices, hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type); pnode->AddRef(); // We're making a new connection, harvest entropy from the time (and our peer count) @@ -487,9 +499,9 @@ void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNet } } -std::string CNode::ConnectionTypeAsString() const +std::string ConnectionTypeAsString(ConnectionType conn_type) { - switch (m_conn_type) { + switch (conn_type) { case ConnectionType::INBOUND: return "inbound"; case ConnectionType::MANUAL: @@ -533,6 +545,11 @@ void CNode::SetAddrLocal(const CService& addrLocalIn) { } } +Network CNode::ConnectedThroughNetwork() const +{ + return m_inbound_onion ? NET_ONION : addr.GetNetClass(); +} + #undef X #define X(name) stats.name = name void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap) @@ -541,6 +558,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap) X(nServices); X(addr); X(addrBind); + stats.m_network = ConnectedThroughNetwork(); stats.m_mapped_as = addr.GetMappedAS(m_asmap); if (m_tx_relay != nullptr) { LOCK(m_tx_relay->cs_filter); @@ -561,8 +579,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap) X(cleanSubVer); } stats.fInbound = IsInboundConn(); - stats.m_manual_connection = IsManualConn(); - X(nStartingHeight); + X(m_bip152_highbandwidth_to); + X(m_bip152_highbandwidth_from); { LOCK(cs_vSend); X(mapSendBytesPerMsgCmd); @@ -573,10 +591,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap) X(mapRecvBytesPerMsgCmd); X(nRecvBytes); } - X(m_legacyWhitelisted); X(m_permissionFlags); if (m_tx_relay != nullptr) { - LOCK(m_tx_relay->cs_feeFilter); stats.minFeeFilter = m_tx_relay->minFeeFilter; } else { stats.minFeeFilter = 0; @@ -602,38 +618,25 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap) CService addrLocalUnlocked = GetAddrLocal(); stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : ""; - stats.m_conn_type_string = ConnectionTypeAsString(); + X(m_conn_type); } #undef X -/** - * Receive bytes from the buffer and deserialize them into messages. - * - * @param[in] pch A pointer to the raw data - * @param[in] nBytes Size of the data - * @param[out] complete Set True if at least one message has been - * deserialized and is ready to be processed - * @return True if the peer should stay connected, - * False if the peer should be disconnected from. - */ -bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete) +bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete) { complete = false; const auto time = GetTime<std::chrono::microseconds>(); LOCK(cs_vRecv); nLastRecv = std::chrono::duration_cast<std::chrono::seconds>(time).count(); - nRecvBytes += nBytes; - while (nBytes > 0) { + nRecvBytes += msg_bytes.size(); + while (msg_bytes.size() > 0) { // absorb network data - int handled = m_deserializer->Read(pch, nBytes); + int handled = m_deserializer->Read(msg_bytes); if (handled < 0) { // Serious header problem, disconnect from the peer. return false; } - pch += handled; - nBytes -= handled; - if (m_deserializer->Complete()) { // decompose a transport agnostic CNetMessage from the deserializer uint32_t out_err_raw_size{0}; @@ -663,13 +666,13 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete return true; } -int V1TransportDeserializer::readHeader(const char *pch, unsigned int nBytes) +int V1TransportDeserializer::readHeader(Span<const uint8_t> msg_bytes) { // copy data to temporary parsing buffer unsigned int nRemaining = CMessageHeader::HEADER_SIZE - nHdrPos; - unsigned int nCopy = std::min(nRemaining, nBytes); + unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size()); - memcpy(&hdrbuf[nHdrPos], pch, nCopy); + memcpy(&hdrbuf[nHdrPos], msg_bytes.data(), nCopy); nHdrPos += nCopy; // if header incomplete, exit @@ -703,18 +706,18 @@ int V1TransportDeserializer::readHeader(const char *pch, unsigned int nBytes) return nCopy; } -int V1TransportDeserializer::readData(const char *pch, unsigned int nBytes) +int V1TransportDeserializer::readData(Span<const uint8_t> msg_bytes) { unsigned int nRemaining = hdr.nMessageSize - nDataPos; - unsigned int nCopy = std::min(nRemaining, nBytes); + unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size()); if (vRecv.size() < nDataPos + nCopy) { // Allocate up to 256 KiB ahead, but never more than the total message size. vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024)); } - hasher.Write({(const unsigned char*)pch, nCopy}); - memcpy(&vRecv[nDataPos], pch, nCopy); + hasher.Write(msg_bytes.first(nCopy)); + memcpy(&vRecv[nDataPos], msg_bytes.data(), nCopy); nDataPos += nCopy; return nCopy; @@ -778,30 +781,30 @@ void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vec CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, header, 0, hdr}; } -size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pnode->cs_vSend) +size_t CConnman::SocketSendData(CNode& node) const { - auto it = pnode->vSendMsg.begin(); + auto it = node.vSendMsg.begin(); size_t nSentSize = 0; - while (it != pnode->vSendMsg.end()) { - const auto &data = *it; - assert(data.size() > pnode->nSendOffset); + while (it != node.vSendMsg.end()) { + const auto& data = *it; + assert(data.size() > node.nSendOffset); int nBytes = 0; { - LOCK(pnode->cs_hSocket); - if (pnode->hSocket == INVALID_SOCKET) + LOCK(node.cs_hSocket); + if (node.hSocket == INVALID_SOCKET) break; - nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); + nBytes = send(node.hSocket, reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); } if (nBytes > 0) { - pnode->nLastSend = GetSystemTimeInSeconds(); - pnode->nSendBytes += nBytes; - pnode->nSendOffset += nBytes; + node.nLastSend = GetSystemTimeInSeconds(); + node.nSendBytes += nBytes; + node.nSendOffset += nBytes; nSentSize += nBytes; - if (pnode->nSendOffset == data.size()) { - pnode->nSendOffset = 0; - pnode->nSendSize -= data.size(); - pnode->fPauseSend = pnode->nSendSize > nSendBufferMaxSize; + if (node.nSendOffset == data.size()) { + node.nSendOffset = 0; + node.nSendSize -= data.size(); + node.fPauseSend = node.nSendSize > nSendBufferMaxSize; it++; } else { // could not send full message; stop sending more @@ -811,10 +814,9 @@ size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pno if (nBytes < 0) { // error int nErr = WSAGetLastError(); - if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) - { - LogPrintf("socket send error %s\n", NetworkErrorString(nErr)); - pnode->CloseSocketDisconnect(); + if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) { + LogPrint(BCLog::NET, "socket send error for peer=%d: %s\n", node.GetId(), NetworkErrorString(nErr)); + node.CloseSocketDisconnect(); } } // couldn't send anything at all @@ -822,30 +824,14 @@ size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pno } } - if (it == pnode->vSendMsg.end()) { - assert(pnode->nSendOffset == 0); - assert(pnode->nSendSize == 0); + if (it == node.vSendMsg.end()) { + assert(node.nSendOffset == 0); + assert(node.nSendSize == 0); } - pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it); + node.vSendMsg.erase(node.vSendMsg.begin(), it); return nSentSize; } -struct NodeEvictionCandidate -{ - NodeId id; - int64_t nTimeConnected; - int64_t nMinPingUsecTime; - int64_t nLastBlockTime; - int64_t nLastTXTime; - bool fRelevantServices; - bool fRelayTxes; - bool fBloomFilter; - CAddress addr; - uint64_t nKeyedNetGroup; - bool prefer_evict; - bool m_is_local; -}; - static bool ReverseCompareNodeMinPingTime(const NodeEvictionCandidate &a, const NodeEvictionCandidate &b) { return a.nMinPingUsecTime > b.nMinPingUsecTime; @@ -901,43 +887,8 @@ static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, elements.erase(elements.end() - eraseSize, elements.end()); } -/** Try to find a connection to evict when the node is full. - * Extreme care must be taken to avoid opening the node to attacker - * triggered network partitioning. - * The strategy used here is to protect a small number of peers - * for each of several distinct characteristics which are difficult - * to forge. In order to partition a node the attacker must be - * simultaneously better at all of them than honest peers. - */ -bool CConnman::AttemptToEvictConnection() +[[nodiscard]] Optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates) { - std::vector<NodeEvictionCandidate> vEvictionCandidates; - { - LOCK(cs_vNodes); - - for (const CNode* node : vNodes) { - if (node->HasPermission(PF_NOBAN)) - continue; - if (!node->IsInboundConn()) - continue; - if (node->fDisconnect) - continue; - bool peer_relay_txes = false; - bool peer_filter_not_null = false; - if (node->m_tx_relay != nullptr) { - LOCK(node->m_tx_relay->cs_filter); - peer_relay_txes = node->m_tx_relay->fRelayTxes; - peer_filter_not_null = node->m_tx_relay->pfilter != nullptr; - } - NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime, - node->nLastBlockTime, node->nLastTXTime, - HasAllDesirableServiceFlags(node->nServices), - peer_relay_txes, peer_filter_not_null, node->addr, node->nKeyedNetGroup, - node->m_prefer_evict, node->addr.IsLocal()}; - vEvictionCandidates.push_back(candidate); - } - } - // Protect connections with certain characteristics // Deterministically select 4 peers to protect by netgroup. @@ -975,7 +926,7 @@ bool CConnman::AttemptToEvictConnection() total_protect_size -= initial_size - vEvictionCandidates.size(); EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, total_protect_size); - if (vEvictionCandidates.empty()) return false; + if (vEvictionCandidates.empty()) return nullopt; // 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) @@ -1007,10 +958,53 @@ bool CConnman::AttemptToEvictConnection() vEvictionCandidates = std::move(mapNetGroupNodes[naMostConnections]); // Disconnect from the network group with the most connections - NodeId evicted = vEvictionCandidates.front().id; + return vEvictionCandidates.front().id; +} + +/** Try to find a connection to evict when the node is full. + * Extreme care must be taken to avoid opening the node to attacker + * triggered network partitioning. + * The strategy used here is to protect a small number of peers + * for each of several distinct characteristics which are difficult + * to forge. In order to partition a node the attacker must be + * simultaneously better at all of them than honest peers. + */ +bool CConnman::AttemptToEvictConnection() +{ + std::vector<NodeEvictionCandidate> vEvictionCandidates; + { + + LOCK(cs_vNodes); + for (const CNode* node : vNodes) { + if (node->HasPermission(PF_NOBAN)) + continue; + if (!node->IsInboundConn()) + continue; + if (node->fDisconnect) + continue; + bool peer_relay_txes = false; + bool peer_filter_not_null = false; + if (node->m_tx_relay != nullptr) { + LOCK(node->m_tx_relay->cs_filter); + peer_relay_txes = node->m_tx_relay->fRelayTxes; + peer_filter_not_null = node->m_tx_relay->pfilter != nullptr; + } + NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime, + node->nLastBlockTime, node->nLastTXTime, + HasAllDesirableServiceFlags(node->nServices), + peer_relay_txes, peer_filter_not_null, node->nKeyedNetGroup, + node->m_prefer_evict, node->addr.IsLocal()}; + vEvictionCandidates.push_back(candidate); + } + } + const Optional<NodeId> node_id_to_evict = SelectNodeToEvict(std::move(vEvictionCandidates)); + if (!node_id_to_evict) { + return false; + } LOCK(cs_vNodes); for (CNode* pnode : vNodes) { - if (pnode->GetId() == evicted) { + if (pnode->GetId() == *node_id_to_evict) { + LogPrint(BCLog::NET, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId()); pnode->fDisconnect = true; return true; } @@ -1035,14 +1029,12 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { NetPermissionFlags permissionFlags = NetPermissionFlags::PF_NONE; hListenSocket.AddSocketPermissionFlags(permissionFlags); AddWhitelistPermissionFlags(permissionFlags, addr); - bool legacyWhitelisted = false; if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_ISIMPLICIT)) { NetPermissions::ClearFlag(permissionFlags, PF_ISIMPLICIT); if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, PF_FORCERELAY); if (gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) NetPermissions::AddFlag(permissionFlags, PF_RELAY); NetPermissions::AddFlag(permissionFlags, PF_MEMPOOL); NetPermissions::AddFlag(permissionFlags, PF_NOBAN); - legacyWhitelisted = true; } { @@ -1061,7 +1053,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } if (!fNetworkActive) { - LogPrintf("connection from %s dropped: not accepting new connections\n", addr.ToString()); + LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToString()); CloseSocket(hSocket); return; } @@ -1113,11 +1105,11 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { if (NetPermissions::HasFlag(permissionFlags, PF_BLOOMFILTER)) { nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM); } - CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND); + + const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end(); + CNode* pnode = new CNode(id, nodeServices, hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND, inbound_onion); pnode->AddRef(); pnode->m_permissionFlags = permissionFlags; - // If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility) - pnode->m_legacyWhitelisted = legacyWhitelisted; pnode->m_prefer_evict = discouraged; m_msgproc->InitializeNode(pnode); @@ -1132,6 +1124,27 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { RandAddEvent((uint32_t)id); } +bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type) +{ + if (conn_type != ConnectionType::OUTBOUND_FULL_RELAY && conn_type != ConnectionType::BLOCK_RELAY) return false; + + const int max_connections = conn_type == ConnectionType::OUTBOUND_FULL_RELAY ? m_max_outbound_full_relay : m_max_outbound_block_relay; + + // Count existing connections + int existing_connections = WITH_LOCK(cs_vNodes, + return std::count_if(vNodes.begin(), vNodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; });); + + // Max connections of specified type already exist + if (existing_connections >= max_connections) return false; + + // Max total outbound connections already exist + CSemaphoreGrant grant(*semOutbound, true); + if (!grant) return false; + + OpenNetworkConnection(CAddress(), false, &grant, address.c_str(), conn_type); + return true; +} + void CConnman::DisconnectNodes() { { @@ -1205,37 +1218,47 @@ void CConnman::NotifyNumConnectionsChanged() } } -void CConnman::InactivityCheck(CNode *pnode) +bool CConnman::InactivityCheck(const CNode& node) const { - int64_t nTime = GetSystemTimeInSeconds(); - if (nTime - pnode->nTimeConnected > m_peer_connect_timeout) - { - if (pnode->nLastRecv == 0 || pnode->nLastSend == 0) - { - LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d from %d\n", m_peer_connect_timeout, pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId()); - pnode->fDisconnect = true; - } - else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL) - { - LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend); - pnode->fDisconnect = true; - } - else if (nTime - pnode->nLastRecv > (pnode->GetCommonVersion() > BIP0031_VERSION ? TIMEOUT_INTERVAL : 90*60)) - { - LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv); - pnode->fDisconnect = true; - } - else if (pnode->nPingNonceSent && pnode->m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL} < GetTime<std::chrono::microseconds>()) - { - LogPrintf("ping timeout: %fs\n", 0.000001 * count_microseconds(GetTime<std::chrono::microseconds>() - pnode->m_ping_start.load())); - pnode->fDisconnect = true; - } - else if (!pnode->fSuccessfullyConnected) - { - LogPrint(BCLog::NET, "version handshake timeout from %d\n", pnode->GetId()); - pnode->fDisconnect = true; - } + // Use non-mockable system time (otherwise these timers will pop when we + // use setmocktime in the tests). + int64_t now = GetSystemTimeInSeconds(); + + if (now <= node.nTimeConnected + m_peer_connect_timeout) { + // Only run inactivity checks if the peer has been connected longer + // than m_peer_connect_timeout. + return false; + } + + if (node.nLastRecv == 0 || node.nLastSend == 0) { + LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", m_peer_connect_timeout, node.nLastRecv != 0, node.nLastSend != 0, node.GetId()); + return true; + } + + if (now > node.nLastSend + TIMEOUT_INTERVAL) { + LogPrint(BCLog::NET, "socket sending timeout: %is peer=%d\n", now - node.nLastSend, node.GetId()); + return true; + } + + if (now > node.nLastRecv + TIMEOUT_INTERVAL) { + LogPrint(BCLog::NET, "socket receive timeout: %is peer=%d\n", now - node.nLastRecv, node.GetId()); + return true; + } + + if (node.nPingNonceSent && node.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL} < GetTime<std::chrono::microseconds>()) { + // We use mockable time for ping timeouts. This means that setmocktime + // may cause pings to time out for peers that have been connected for + // longer than m_peer_connect_timeout. + LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(GetTime<std::chrono::microseconds>() - node.m_ping_start.load()), node.GetId()); + return true; + } + + if (!node.fSuccessfullyConnected) { + LogPrint(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId()); + return true; } + + return false; } bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set) @@ -1452,18 +1475,18 @@ void CConnman::SocketHandler() if (recvSet || errorSet) { // typical socket buffer is 8K-64K - char pchBuf[0x10000]; + uint8_t pchBuf[0x10000]; int nBytes = 0; { LOCK(pnode->cs_hSocket); if (pnode->hSocket == INVALID_SOCKET) continue; - nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT); + nBytes = recv(pnode->hSocket, (char*)pchBuf, sizeof(pchBuf), MSG_DONTWAIT); } if (nBytes > 0) { bool notify = false; - if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify)) + if (!pnode->ReceiveMsgBytes(Span<const uint8_t>(pchBuf, nBytes), notify)) pnode->CloseSocketDisconnect(); RecordBytesRecv(nBytes); if (notify) { @@ -1505,19 +1528,13 @@ void CConnman::SocketHandler() } } - // - // Send - // - if (sendSet) - { - LOCK(pnode->cs_vSend); - size_t nBytes = SocketSendData(pnode); - if (nBytes) { - RecordBytesSent(nBytes); - } + if (sendSet) { + // Send data + size_t bytes_sent = WITH_LOCK(pnode->cs_vSend, return SocketSendData(*pnode)); + if (bytes_sent) RecordBytesSent(bytes_sent); } - InactivityCheck(pnode); + if (InactivityCheck(*pnode)) pnode->fDisconnect = true; } { LOCK(cs_vNodes); @@ -1545,121 +1562,6 @@ void CConnman::WakeMessageHandler() condMsgProc.notify_one(); } - - - - - -#ifdef USE_UPNP -static CThreadInterrupt g_upnp_interrupt; -static std::thread g_upnp_thread; -static void ThreadMapPort() -{ - std::string port = strprintf("%u", GetListenPort()); - const char * multicastif = nullptr; - const char * minissdpdpath = nullptr; - struct UPNPDev * devlist = nullptr; - char lanaddr[64]; - - int error = 0; -#if MINIUPNPC_API_VERSION < 14 - devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); -#else - devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error); -#endif - - struct UPNPUrls urls; - struct IGDdatas data; - int r; - - r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); - if (r == 1) - { - if (fDiscover) { - char externalIPAddress[40]; - r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); - if (r != UPNPCOMMAND_SUCCESS) { - LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r); - } else { - if (externalIPAddress[0]) { - CNetAddr resolved; - if (LookupHost(externalIPAddress, resolved, false)) { - LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString()); - AddLocal(resolved, LOCAL_UPNP); - } - } else { - LogPrintf("UPnP: GetExternalIPAddress failed.\n"); - } - } - } - - std::string strDesc = PACKAGE_NAME " " + FormatFullVersion(); - - do { - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); - - if (r != UPNPCOMMAND_SUCCESS) { - LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r)); - } else { - LogPrintf("UPnP Port Mapping successful.\n"); - } - } while (g_upnp_interrupt.sleep_for(std::chrono::minutes(20))); - - r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); - LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r); - freeUPNPDevlist(devlist); devlist = nullptr; - FreeUPNPUrls(&urls); - } else { - LogPrintf("No valid UPnP IGDs found\n"); - freeUPNPDevlist(devlist); devlist = nullptr; - if (r != 0) - FreeUPNPUrls(&urls); - } -} - -void StartMapPort() -{ - if (!g_upnp_thread.joinable()) { - assert(!g_upnp_interrupt); - g_upnp_thread = std::thread((std::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort))); - } -} - -void InterruptMapPort() -{ - if(g_upnp_thread.joinable()) { - g_upnp_interrupt(); - } -} - -void StopMapPort() -{ - if(g_upnp_thread.joinable()) { - g_upnp_thread.join(); - g_upnp_interrupt.reset(); - } -} - -#else -void StartMapPort() -{ - // Intentionally left blank. -} -void InterruptMapPort() -{ - // Intentionally left blank. -} -void StopMapPort() -{ - // Intentionally left blank. -} -#endif - - - - - - void CConnman::ThreadDNSAddressSeed() { FastRandomContext rng; @@ -1811,22 +1713,36 @@ void CConnman::SetTryNewOutboundPeer(bool flag) // Return the number of peers we have over our outbound connection limit // Exclude peers that are marked for disconnect, or are going to be -// disconnected soon (eg one-shots and feelers) +// disconnected soon (eg ADDR_FETCH and FEELER) // Also exclude peers that haven't finished initial connection handshake yet // (so that we don't decide we're over our desired connection limit, and then // evict some peer that has finished the handshake) -int CConnman::GetExtraOutboundCount() +int CConnman::GetExtraFullOutboundCount() { - int nOutbound = 0; + int full_outbound_peers = 0; { LOCK(cs_vNodes); for (const CNode* pnode : vNodes) { - if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsOutboundOrBlockRelayConn()) { - ++nOutbound; + if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsFullOutboundConn()) { + ++full_outbound_peers; } } } - return std::max(nOutbound - m_max_outbound_full_relay - m_max_outbound_block_relay, 0); + return std::max(full_outbound_peers - m_max_outbound_full_relay, 0); +} + +int CConnman::GetExtraBlockRelayCount() +{ + int block_relay_peers = 0; + { + LOCK(cs_vNodes); + for (const CNode* pnode : vNodes) { + if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) { + ++block_relay_peers; + } + } + } + return std::max(block_relay_peers - m_max_outbound_block_relay, 0); } void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) @@ -1857,6 +1773,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) // Minimum time before next feeler connection (in microseconds). int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL); + int64_t nNextExtraBlockRelay = PoissonNextSend(nStart*1000*1000, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); while (!interruptNet) { ProcessAddrFetch(); @@ -1919,23 +1836,53 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY; int64_t nTime = GetTimeMicros(); + bool anchor = false; bool fFeeler = false; // Determine what type of connection to open. Opening - // OUTBOUND_FULL_RELAY connections gets the highest priority until we + // BLOCK_RELAY connections to addresses from anchors.dat gets the highest + // priority. Then we open OUTBOUND_FULL_RELAY priority until we // meet our full-relay capacity. Then we open BLOCK_RELAY connection // until we hit our block-relay-only peer limit. // GetTryNewOutboundPeer() gets set when a stale tip is detected, so we // try opening an additional OUTBOUND_FULL_RELAY connection. If none of - // these conditions are met, check the nNextFeeler timer to decide if - // we should open a FEELER. + // these conditions are met, check to see if it's time to try an extra + // block-relay-only peer (to confirm our tip is current, see below) or the nNextFeeler + // timer to decide if we should open a FEELER. - if (nOutboundFullRelay < m_max_outbound_full_relay) { + if (!m_anchors.empty() && (nOutboundBlockRelay < m_max_outbound_block_relay)) { + conn_type = ConnectionType::BLOCK_RELAY; + anchor = true; + } else if (nOutboundFullRelay < m_max_outbound_full_relay) { // OUTBOUND_FULL_RELAY } else if (nOutboundBlockRelay < m_max_outbound_block_relay) { conn_type = ConnectionType::BLOCK_RELAY; } else if (GetTryNewOutboundPeer()) { // OUTBOUND_FULL_RELAY + } else if (nTime > nNextExtraBlockRelay && m_start_extra_block_relay_peers) { + // Periodically connect to a peer (using regular outbound selection + // methodology from addrman) and stay connected long enough to sync + // headers, but not much else. + // + // Then disconnect the peer, if we haven't learned anything new. + // + // The idea is to make eclipse attacks very difficult to pull off, + // because every few minutes we're finding a new peer to learn headers + // from. + // + // This is similar to the logic for trying extra outbound (full-relay) + // peers, except: + // - we do this all the time on a poisson timer, rather than just when + // our tip is stale + // - we potentially disconnect our next-youngest block-relay-only peer, if our + // newest block-relay-only peer delivers a block more recently. + // See the eviction logic in net_processing.cpp. + // + // Because we can promote these connections to block-relay-only + // connections, they do not get their own ConnectionType enum + // (similar to how we deal with extra outbound peers). + nNextExtraBlockRelay = PoissonNextSend(nTime, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); + conn_type = ConnectionType::BLOCK_RELAY; } else if (nTime > nNextFeeler) { nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL); conn_type = ConnectionType::FEELER; @@ -1951,11 +1898,48 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) int nTries = 0; while (!interruptNet) { - CAddrInfo addr = addrman.SelectTriedCollision(); + if (anchor && !m_anchors.empty()) { + const CAddress addr = m_anchors.back(); + m_anchors.pop_back(); + if (!addr.IsValid() || IsLocal(addr) || !IsReachable(addr) || + !HasAllDesirableServiceFlags(addr.nServices) || + setConnected.count(addr.GetGroup(addrman.m_asmap))) continue; + addrConnect = addr; + LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToString()); + break; + } + + // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, + // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates + // already-connected network ranges, ...) before trying new addrman addresses. + nTries++; + if (nTries > 100) + break; + + CAddrInfo addr; - // SelectTriedCollision returns an invalid address if it is empty. - if (!fFeeler || !addr.IsValid()) { - addr = addrman.Select(fFeeler); + if (fFeeler) { + // First, try to get a tried table collision address. This returns + // an empty (invalid) address if there are no collisions to try. + addr = addrman.SelectTriedCollision(); + + if (!addr.IsValid()) { + // No tried table collisions. Select a new table address + // for our feeler. + addr = addrman.Select(true); + } else if (AlreadyConnectedToAddress(addr)) { + // If test-before-evict logic would have us connect to a + // peer that we're already connected to, just mark that + // address as Good(). We won't be able to initiate the + // connection anyway, so this avoids inadvertently evicting + // a currently-connected peer. + addrman.Good(addr); + // Select a new table address for our feeler instead. + addr = addrman.Select(true); + } + } else { + // Not a feeler + addr = addrman.Select(); } // Require outbound connections, other than feelers, to be to distinct network groups @@ -1968,13 +1952,6 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) break; } - // If we didn't find an appropriate destination after trying 100 addresses fetched from addrman, - // stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates - // already-connected network ranges, ...) before trying new addrman addresses. - nTries++; - if (nTries > 100) - break; - if (!IsReachable(addr)) continue; @@ -1991,7 +1968,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) continue; } - // do not allow non-default ports, unless after 50 invalid addresses selected already + // Do not allow non-default ports, unless after 50 invalid + // addresses selected already. This is to prevent malicious peers + // from advertising themselves as a service on another host and + // port, causing a DoS attack as nodes around the network attempt + // to connect to it fruitlessly. if (addr.GetPort() != Params().GetDefaultPort() && nTries < 50) continue; @@ -2014,6 +1995,19 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) } } +std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const +{ + std::vector<CAddress> ret; + LOCK(cs_vNodes); + for (const CNode* pnode : vNodes) { + if (pnode->IsBlockOnlyConn()) { + ret.push_back(pnode->addr); + } + } + + return ret; +} + std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() { std::vector<AddedNodeInfo> ret; @@ -2111,7 +2105,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai } if (!pszDest) { bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect)); - if (IsLocal(addrConnect) || FindNode(static_cast<CNetAddr>(addrConnect)) || banned_or_discouraged || FindNode(addrConnect.ToStringIPPort())) { + if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) { return; } } else if (FindNode(std::string(pszDest))) @@ -2241,10 +2235,6 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, } vhListenSocket.push_back(ListenSocket(hListenSocket, permissions)); - - if (addrBind.IsRoutable() && fDiscover && (permissions & PF_NOBAN) == 0) - AddLocal(addrBind, LOCAL_BIND); - return true; } @@ -2338,10 +2328,18 @@ bool CConnman::Bind(const CService &addr, unsigned int flags, NetPermissionFlags } return false; } + + if (addr.IsRoutable() && fDiscover && !(flags & BF_DONT_ADVERTISE) && !(permissions & PF_NOBAN)) { + AddLocal(addr, LOCAL_BIND); + } + return true; } -bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds) +bool CConnman::InitBinds( + const std::vector<CService>& binds, + const std::vector<NetWhitebindPermissions>& whiteBinds, + const std::vector<CService>& onion_binds) { bool fBound = false; for (const auto& addrBind : binds) { @@ -2352,11 +2350,16 @@ bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<N } if (binds.empty() && whiteBinds.empty()) { struct in_addr inaddr_any; - inaddr_any.s_addr = INADDR_ANY; + inaddr_any.s_addr = htonl(INADDR_ANY); struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT; fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::PF_NONE); fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::PF_NONE); } + + for (const auto& addr_bind : onion_binds) { + fBound |= Bind(addr_bind, BF_EXPLICIT | BF_DONT_ADVERTISE, NetPermissionFlags::PF_NONE); + } + return fBound; } @@ -2364,18 +2367,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) { Init(connOptions); - { - LOCK(cs_totalBytesRecv); - nTotalBytesRecv = 0; - } - { - LOCK(cs_totalBytesSent); - nTotalBytesSent = 0; - nMaxOutboundTotalBytesSentInCycle = 0; - nMaxOutboundCycleStartTime = 0; - } - - if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) { + if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds, connOptions.onion_binds)) { if (clientInterface) { clientInterface->ThreadSafeMessageBox( _("Failed to listen on any port. Use -listen=0 if you want this."), @@ -2404,6 +2396,15 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) } } + if (m_use_addrman_outgoing) { + // Load addresses from anchors.dat + m_anchors = ReadAnchors(GetDataDir() / ANCHORS_DATABASE_FILENAME); + if (m_anchors.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) { + m_anchors.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS); + } + LogPrintf("%i block-relay-only anchors will be tried for connections.\n", m_anchors.size()); + } + uiInterface.InitMessage(_("Starting network threads...").translated); fAddressesInitialized = true; @@ -2519,6 +2520,15 @@ void CConnman::StopNodes() if (fAddressesInitialized) { DumpAddresses(); fAddressesInitialized = false; + + if (m_use_addrman_outgoing) { + // Anchor connections are only dumped during clean shutdown. + std::vector<CAddress> anchors_to_dump = GetCurrentBlockRelayOnlyConns(); + if (anchors_to_dump.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) { + anchors_to_dump.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS); + } + DumpAnchors(GetDataDir() / ANCHORS_DATABASE_FILENAME, anchors_to_dump); + } } // Close sockets @@ -2548,7 +2558,7 @@ void CConnman::DeleteNode(CNode* pnode) { assert(pnode); bool fUpdateConnectionTime = false; - m_msgproc->FinalizeNode(pnode->GetId(), fUpdateConnectionTime); + m_msgproc->FinalizeNode(*pnode, fUpdateConnectionTime); if (fUpdateConnectionTime) { addrman.Connected(pnode->addr); } @@ -2684,6 +2694,7 @@ bool CConnman::DisconnectNode(const std::string& strNode) { LOCK(cs_vNodes); if (CNode* pnode = FindNode(strNode)) { + LogPrint(BCLog::NET, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId()); pnode->fDisconnect = true; return true; } @@ -2696,6 +2707,7 @@ bool CConnman::DisconnectNode(const CSubNet& subnet) LOCK(cs_vNodes); for (CNode* pnode : vNodes) { if (subnet.Match(pnode->addr)) { + LogPrint(BCLog::NET, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId()); pnode->fDisconnect = true; disconnected = true; } @@ -2713,6 +2725,7 @@ bool CConnman::DisconnectNode(NodeId id) LOCK(cs_vNodes); for(CNode* pnode : vNodes) { if (id == pnode->GetId()) { + LogPrint(BCLog::NET, "disconnect by id peer=%d; disconnecting\n", pnode->GetId()); pnode->fDisconnect = true; return true; } @@ -2731,8 +2744,8 @@ void CConnman::RecordBytesSent(uint64_t bytes) LOCK(cs_totalBytesSent); nTotalBytesSent += bytes; - uint64_t now = GetTime(); - if (nMaxOutboundCycleStartTime + nMaxOutboundTimeframe < now) + const auto now = GetTime<std::chrono::seconds>(); + if (nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME < now) { // timeframe expired, reset cycle nMaxOutboundCycleStartTime = now; @@ -2743,48 +2756,29 @@ void CConnman::RecordBytesSent(uint64_t bytes) nMaxOutboundTotalBytesSentInCycle += bytes; } -void CConnman::SetMaxOutboundTarget(uint64_t limit) -{ - LOCK(cs_totalBytesSent); - nMaxOutboundLimit = limit; -} - uint64_t CConnman::GetMaxOutboundTarget() { LOCK(cs_totalBytesSent); return nMaxOutboundLimit; } -uint64_t CConnman::GetMaxOutboundTimeframe() +std::chrono::seconds CConnman::GetMaxOutboundTimeframe() { - LOCK(cs_totalBytesSent); - return nMaxOutboundTimeframe; + return MAX_UPLOAD_TIMEFRAME; } -uint64_t CConnman::GetMaxOutboundTimeLeftInCycle() +std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() { LOCK(cs_totalBytesSent); if (nMaxOutboundLimit == 0) - return 0; + return 0s; - if (nMaxOutboundCycleStartTime == 0) - return nMaxOutboundTimeframe; + if (nMaxOutboundCycleStartTime.count() == 0) + return MAX_UPLOAD_TIMEFRAME; - uint64_t cycleEndTime = nMaxOutboundCycleStartTime + nMaxOutboundTimeframe; - uint64_t now = GetTime(); - return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime(); -} - -void CConnman::SetMaxOutboundTimeframe(uint64_t timeframe) -{ - LOCK(cs_totalBytesSent); - if (nMaxOutboundTimeframe != timeframe) - { - // reset measure-cycle in case of changing - // the timeframe - nMaxOutboundCycleStartTime = GetTime(); - } - nMaxOutboundTimeframe = timeframe; + const std::chrono::seconds cycleEndTime = nMaxOutboundCycleStartTime + MAX_UPLOAD_TIMEFRAME; + const auto now = GetTime<std::chrono::seconds>(); + return (cycleEndTime < now) ? 0s : cycleEndTime - now; } bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) @@ -2796,8 +2790,8 @@ bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) if (historicalBlockServingLimit) { // keep a large enough buffer to at least relay each block once - uint64_t timeLeftInCycle = GetMaxOutboundTimeLeftInCycle(); - uint64_t buffer = timeLeftInCycle / 600 * MAX_BLOCK_SERIALIZED_SIZE; + const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle(); + const uint64_t buffer = timeLeftInCycle / std::chrono::minutes{10} * MAX_BLOCK_SERIALIZED_SIZE; if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer) return true; } @@ -2833,35 +2827,22 @@ ServiceFlags CConnman::GetLocalServices() const return nLocalServices; } -void CConnman::SetBestHeight(int height) -{ - nBestHeight.store(height, std::memory_order_release); -} - -int CConnman::GetBestHeight() const -{ - return nBestHeight.load(std::memory_order_acquire); -} - 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, ConnectionType conn_type_in) +CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion) : nTimeConnected(GetSystemTimeInSeconds()), - addr(addrIn), - addrBind(addrBindIn), - nKeyedNetGroup(nKeyedNetGroupIn), - // Don't relay addr messages to peers that we connect to as block-relay-only - // peers (to prevent adversaries from inferring these links from addr - // traffic). - id(idIn), - nLocalHostNonce(nLocalHostNonceIn), - m_conn_type(conn_type_in), - nLocalServices(nLocalServicesIn), - nMyStartingHeight(nMyStartingHeightIn) -{ + addr(addrIn), + addrBind(addrBindIn), + nKeyedNetGroup(nKeyedNetGroupIn), + id(idIn), + nLocalHostNonce(nLocalHostNonceIn), + m_conn_type(conn_type_in), + nLocalServices(nLocalServicesIn), + m_inbound_onion(inbound_onion) +{ + if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND); hSocket = hSocketIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; - hashContinue = uint256(); if (conn_type_in != ConnectionType::BLOCK_RELAY) { m_tx_relay = MakeUnique<TxRelay>(); } @@ -2921,7 +2902,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg) // If write queue empty, attempt "optimistic write" if (optimisticSend == true) - nBytesSent = SocketSendData(pnode); + nBytesSent = SocketSendData(*pnode); } if (nBytesSent) RecordBytesSent(nBytesSent); @@ -14,7 +14,6 @@ #include <compat.h> #include <crypto/siphash.h> #include <hash.h> -#include <limitedmap.h> #include <net_permissions.h> #include <netaddress.h> #include <optional.h> @@ -25,19 +24,16 @@ #include <sync.h> #include <threadinterrupt.h> #include <uint256.h> +#include <util/check.h> #include <atomic> +#include <condition_variable> #include <cstdint> #include <deque> #include <map> -#include <thread> #include <memory> -#include <condition_variable> - -#ifndef WIN32 -#include <arpa/inet.h> -#endif - +#include <thread> +#include <vector> class CScheduler; class CNode; @@ -53,6 +49,8 @@ static const bool DEFAULT_WHITELISTFORCERELAY = false; static const int TIMEOUT_INTERVAL = 20 * 60; /** Run the feeler connection loop once every 2 minutes or 120 seconds. **/ static const int FEELER_INTERVAL = 120; +/** Run the extra block-relay-only connection loop once every 5 minutes. **/ +static const int EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL = 300; /** The maximum number of addresses from our addrman to return in response to a getaddr message. */ static constexpr size_t MAX_ADDR_TO_SEND = 1000; /** Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable). */ @@ -69,18 +67,10 @@ static const int MAX_BLOCK_RELAY_ONLY_CONNECTIONS = 2; static const int MAX_FEELER_CONNECTIONS = 1; /** -listen default */ static const bool DEFAULT_LISTEN = true; -/** -upnp default */ -#ifdef USE_UPNP -static const bool DEFAULT_UPNP = USE_UPNP; -#else -static const bool DEFAULT_UPNP = false; -#endif /** The maximum number of peer connections to maintain. */ static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125; /** The default for -maxuploadtarget. 0 = Unlimited */ -static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; -/** The default timeframe for -maxuploadtarget. 1 day. */ -static const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24; +static constexpr uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0; /** Default for blocks only*/ static const bool DEFAULT_BLOCKSONLY = false; /** -peertimeout default */ @@ -116,17 +106,13 @@ struct CSerializedNetMsg std::string m_type; }; -const std::vector<std::string> CONNECTION_TYPE_DOC{ - "outbound-full-relay (default automatic connections)", - "block-relay-only (does not relay transactions or addresses)", - "inbound (initiated by the peer)", - "manual (added via addnode RPC or -addnode/-connect configuration options)", - "addr-fetch (short-lived automatic connection for soliciting addresses)", - "feeler (short-lived automatic connection for testing addresses)"}; - /** Different types of connections to a peer. This enum encapsulates the * information we have available at the time of opening or accepting the - * connection. Aside from INBOUND, all types are initiated by us. */ + * connection. Aside from INBOUND, all types are initiated by us. + * + * If adding or removing types, please update CONNECTION_TYPE_DOC in + * src/rpc/net.cpp and src/qt/rpcconsole.cpp, as well as the descriptions in + * src/qt/guiutil.cpp and src/bitcoin-cli.cpp::NetinfoRequestHandler. */ enum class ConnectionType { /** * Inbound connections are those initiated by a peer. This is the only @@ -137,7 +123,7 @@ enum class ConnectionType { /** * These are the default connections that we use to connect with the - * network. There is no restriction on what is relayed- by default we relay + * network. There is no restriction on what is relayed; by default we relay * blocks, addresses & transactions. We automatically attempt to open * MAX_OUTBOUND_FULL_RELAY_CONNECTIONS using addresses from our AddrMan. */ @@ -145,18 +131,27 @@ enum class ConnectionType { /** - * We open manual connections to addresses that users explicitly inputted - * via the addnode RPC, or the -connect command line argument. Even if a + * We open manual connections to addresses that users explicitly requested + * via the addnode RPC or the -addnode/-connect configuration options. Even if a * manual connection is misbehaving, we do not automatically disconnect or * add it to our discouragement filter. */ MANUAL, /** - * Feeler connections are short lived connections used to increase the - * number of connectable addresses in our AddrMan. Approximately every - * FEELER_INTERVAL, we attempt to connect to a random address from the new - * table. If successful, we add it to the tried table. + * Feeler connections are short-lived connections made to check that a node + * is alive. They can be useful for: + * - test-before-evict: if one of the peers is considered for eviction from + * our AddrMan because another peer is mapped to the same slot in the tried table, + * evict only if this longer-known peer is offline. + * - move node addresses from New to Tried table, so that we have more + * connectable addresses in our AddrMan. + * Note that in the literature ("Eclipse Attacks on Bitcoin’s Peer-to-Peer Network") + * only the latter feature is referred to as "feeler connections", + * although in our codebase feeler connections encompass test-before-evict as well. + * We make these connections approximately every FEELER_INTERVAL: + * first we resolve previously found collisions if they exist (test-before-evict), + * otherwise we connect to a node from the new table. */ FEELER, @@ -165,7 +160,9 @@ enum class ConnectionType { * attacks. By not relaying transactions or addresses, these connections * are harder to detect by a third party, thus helping obfuscate the * network topology. We automatically attempt to open - * MAX_BLOCK_RELAY_ONLY_CONNECTIONS using addresses from our AddrMan. + * MAX_BLOCK_RELAY_ONLY_ANCHORS using addresses from our anchors.dat. Then + * addresses from our AddrMan if MAX_BLOCK_RELAY_ONLY_CONNECTIONS + * isn't reached yet. */ BLOCK_RELAY, @@ -178,449 +175,17 @@ enum class ConnectionType { ADDR_FETCH, }; -class NetEventsInterface; -class CConnman -{ -public: - - enum NumConnections { - CONNECTIONS_NONE = 0, - CONNECTIONS_IN = (1U << 0), - CONNECTIONS_OUT = (1U << 1), - CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT), - }; - - struct Options - { - ServiceFlags nLocalServices = NODE_NONE; - int nMaxConnections = 0; - int m_max_outbound_full_relay = 0; - int m_max_outbound_block_relay = 0; - int nMaxAddnode = 0; - int nMaxFeeler = 0; - 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; - uint64_t nMaxOutboundLimit = 0; - int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT; - std::vector<std::string> vSeedNodes; - std::vector<NetWhitelistPermissions> vWhitelistedRange; - std::vector<NetWhitebindPermissions> vWhiteBinds; - std::vector<CService> vBinds; - bool m_use_addrman_outgoing = true; - std::vector<std::string> m_specified_outgoing; - std::vector<std::string> m_added_nodes; - std::vector<bool> m_asmap; - }; - - void Init(const Options& connOptions) { - nLocalServices = connOptions.nLocalServices; - nMaxConnections = connOptions.nMaxConnections; - m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections); - m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay; - m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing; - nMaxAddnode = connOptions.nMaxAddnode; - nMaxFeeler = connOptions.nMaxFeeler; - m_max_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler; - nBestHeight = connOptions.nBestHeight; - clientInterface = connOptions.uiInterface; - m_banman = connOptions.m_banman; - m_msgproc = connOptions.m_msgproc; - nSendBufferMaxSize = connOptions.nSendBufferMaxSize; - nReceiveFloodSize = connOptions.nReceiveFloodSize; - m_peer_connect_timeout = connOptions.m_peer_connect_timeout; - { - LOCK(cs_totalBytesSent); - nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; - nMaxOutboundLimit = connOptions.nMaxOutboundLimit; - } - vWhitelistedRange = connOptions.vWhitelistedRange; - { - LOCK(cs_vAddedNodes); - vAddedNodes = connOptions.m_added_nodes; - } - } - - CConnman(uint64_t seed0, uint64_t seed1, bool network_active = true); - ~CConnman(); - bool Start(CScheduler& scheduler, const Options& options); - - void StopThreads(); - void StopNodes(); - void Stop() - { - StopThreads(); - StopNodes(); - }; - - void Interrupt(); - bool GetNetworkActive() const { return fNetworkActive; }; - bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; - void SetNetworkActive(bool active); - void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type); - bool CheckIncomingNonce(uint64_t nonce); - - bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func); - - void PushMessage(CNode* pnode, CSerializedNetMsg&& msg); - - using NodeFn = std::function<void(CNode*)>; - void ForEachNode(const NodeFn& func) - { - LOCK(cs_vNodes); - for (auto&& node : vNodes) { - if (NodeFullyConnected(node)) - func(node); - } - }; - - void ForEachNode(const NodeFn& func) const - { - LOCK(cs_vNodes); - for (auto&& node : vNodes) { - if (NodeFullyConnected(node)) - func(node); - } - }; - - template<typename Callable, typename CallableAfter> - void ForEachNodeThen(Callable&& pre, CallableAfter&& post) - { - LOCK(cs_vNodes); - for (auto&& node : vNodes) { - if (NodeFullyConnected(node)) - pre(node); - } - post(); - }; - - template<typename Callable, typename CallableAfter> - void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const - { - LOCK(cs_vNodes); - for (auto&& node : vNodes) { - if (NodeFullyConnected(node)) - pre(node); - } - post(); - }; - - // Addrman functions - void SetServices(const CService &addr, ServiceFlags nServices); - void MarkAddressGood(const CAddress& addr); - bool AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0); - std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct); - /** - * Cache is used to minimize topology leaks, so it should - * be used for all non-trusted calls, for example, p2p. - * A non-malicious call (from RPC or a peer with addr permission) should - * call the function without a parameter to avoid using the cache. - */ - std::vector<CAddress> GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct); - - // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding - // a peer that is better than all our current peers. - void SetTryNewOutboundPeer(bool flag); - bool GetTryNewOutboundPeer(); - - // Return the number of outbound peers we have in excess of our target (eg, - // if we previously called SetTryNewOutboundPeer(true), and have since set - // to false, we may have extra peers that we wish to disconnect). This may - // return a value less than (num_outbound_connections - num_outbound_slots) - // in cases where some outbound connections are not yet fully connected, or - // not yet fully disconnected. - int GetExtraOutboundCount(); - - bool AddNode(const std::string& node); - bool RemoveAddedNode(const std::string& node); - std::vector<AddedNodeInfo> GetAddedNodeInfo(); - - 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); - - //! Used to convey which local services we are offering peers during node - //! connection. - //! - //! The data returned by this is used in CNode construction, - //! which is used to advertise which services we are offering - //! that peer during `net_processing.cpp:PushNodeVersion()`. - ServiceFlags GetLocalServices() const; - - //!set the max outbound target in bytes - void SetMaxOutboundTarget(uint64_t limit); - uint64_t GetMaxOutboundTarget(); - - //!set the timeframe for the max outbound target - 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 - bool OutboundTargetReached(bool historicalBlockServingLimit); - - //! 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 - uint64_t GetMaxOutboundTimeLeftInCycle(); - - uint64_t GetTotalBytesRecv(); - uint64_t GetTotalBytesSent(); - - void SetBestHeight(int height); - int GetBestHeight() const; - - /** Get a unique deterministic randomizer. */ - CSipHasher GetDeterministicRandomizer(uint64_t id) const; - - unsigned int GetReceiveFloodSize() const; - - void WakeMessageHandler(); - - /** Attempts to obfuscate tx time through exponentially distributed emitting. - Works assuming that a single interval is used. - Variable intervals will result in privacy decrease. - */ - int64_t PoissonNextSendInbound(int64_t now, int average_interval_seconds); - - void SetAsmap(std::vector<bool> asmap) { addrman.m_asmap = std::move(asmap); } - -private: - struct ListenSocket { - public: - SOCKET socket; - inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); } - ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {} - private: - NetPermissionFlags m_permissions; - }; - - bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions); - bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions); - bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds); - void ThreadOpenAddedConnections(); - void AddAddrFetch(const std::string& strDest); - void ProcessAddrFetch(); - void ThreadOpenConnections(std::vector<std::string> connect); - void ThreadMessageHandler(); - void AcceptConnection(const ListenSocket& hListenSocket); - void DisconnectNodes(); - void NotifyNumConnectionsChanged(); - void InactivityCheck(CNode *pnode); - bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set); - void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set); - void SocketHandler(); - void ThreadSocketHandler(); - void ThreadDNSAddressSeed(); - - uint64_t CalculateKeyedNetGroup(const CAddress& ad) const; - - CNode* FindNode(const CNetAddr& ip); - CNode* FindNode(const CSubNet& subNet); - CNode* FindNode(const std::string& addrName); - CNode* FindNode(const CService& addr); - - bool AttemptToEvictConnection(); - CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type); - void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const; - - void DeleteNode(CNode* pnode); - - NodeId GetNewNodeId(); - - size_t SocketSendData(CNode *pnode) const; - void DumpAddresses(); - - // Network stats - void RecordBytesRecv(uint64_t bytes); - void RecordBytesSent(uint64_t bytes); - - // Whether the node should be passed out in ForEach* callbacks - static bool NodeFullyConnected(const CNode* pnode); - - // Network usage totals - RecursiveMutex cs_totalBytesRecv; - RecursiveMutex cs_totalBytesSent; - uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0}; - uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0}; - - // outbound limit & stats - uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent); - uint64_t nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent); - uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent); - uint64_t nMaxOutboundTimeframe GUARDED_BY(cs_totalBytesSent); - - // P2P timeout in seconds - int64_t m_peer_connect_timeout; - - // Whitelisted ranges. Any node connecting from these is automatically - // whitelisted (as well as those connecting to whitelisted binds). - std::vector<NetWhitelistPermissions> vWhitelistedRange; - - unsigned int nSendBufferMaxSize{0}; - unsigned int nReceiveFloodSize{0}; - - std::vector<ListenSocket> vhListenSocket; - std::atomic<bool> fNetworkActive{true}; - bool fAddressesInitialized{false}; - CAddrMan addrman; - std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex); - RecursiveMutex m_addr_fetches_mutex; - std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes); - RecursiveMutex cs_vAddedNodes; - std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes); - std::list<CNode*> vNodesDisconnected; - mutable RecursiveMutex cs_vNodes; - std::atomic<NodeId> nLastNodeId{0}; - unsigned int nPrevNodeCount{0}; - - /** - * Cache responses to addr requests to minimize privacy leak. - * Attack example: scraping addrs in real-time may allow an attacker - * to infer new connections of the victim by detecting new records - * with fresh timestamps (per self-announcement). - */ - struct CachedAddrResponse { - std::vector<CAddress> m_addrs_response_cache; - std::chrono::microseconds m_cache_entry_expiration{0}; - }; - - /** - * Addr responses stored in different caches - * per (network, local socket) prevent cross-network node identification. - * If a node for example is multi-homed under Tor and IPv6, - * a single cache (or no cache at all) would let an attacker - * to easily detect that it is the same node by comparing responses. - * Indexing by local socket prevents leakage when a node has multiple - * listening addresses on the same network. - * - * The used memory equals to 1000 CAddress records (or around 40 bytes) per - * distinct Network (up to 5) we have/had an inbound peer from, - * resulting in at most ~196 KB. Every separate local socket may - * add up to ~196 KB extra. - */ - std::map<uint64_t, CachedAddrResponse> m_addr_response_caches; - - /** - * Services this instance offers. - * - * This data is replicated in each CNode instance we create during peer - * connection (in ConnectNode()) under a member also called - * nLocalServices. - * - * This data is not marked const, but after being set it should not - * change. See the note in CNode::nLocalServices documentation. - * - * \sa CNode::nLocalServices - */ - ServiceFlags nLocalServices; - - std::unique_ptr<CSemaphore> semOutbound; - std::unique_ptr<CSemaphore> semAddnode; - int nMaxConnections; - - // How many full-relay (tx, block, addr) outbound peers we want - int m_max_outbound_full_relay; - - // How many block-relay only outbound peers we want - // We do not relay tx or addr messages with these peers - int m_max_outbound_block_relay; - - int nMaxAddnode; - int nMaxFeeler; - int m_max_outbound; - bool m_use_addrman_outgoing; - std::atomic<int> nBestHeight; - CClientUIInterface* clientInterface; - NetEventsInterface* m_msgproc; - /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */ - BanMan* m_banman; - - /** SipHasher seeds for deterministic randomness */ - const uint64_t nSeed0, nSeed1; - - /** flag for waking the message processor. */ - bool fMsgProcWake GUARDED_BY(mutexMsgProc); - - std::condition_variable condMsgProc; - Mutex mutexMsgProc; - std::atomic<bool> flagInterruptMsgProc{false}; - - CThreadInterrupt interruptNet; - - std::thread threadDNSAddressSeed; - std::thread threadSocketHandler; - std::thread threadOpenAddedConnections; - std::thread threadOpenConnections; - std::thread threadMessageHandler; - - /** flag for deciding to connect to an extra outbound peer, - * in excess of m_max_outbound_full_relay - * This takes the place of a feeler connection */ - std::atomic_bool m_try_another_outbound_peer; - - std::atomic<int64_t> m_next_send_inv_to_incoming{0}; - - friend struct CConnmanTest; - friend struct ConnmanTestMsg; -}; +/** Convert ConnectionType enum to a string value */ +std::string ConnectionTypeAsString(ConnectionType conn_type); void Discover(); -void StartMapPort(); -void InterruptMapPort(); -void StopMapPort(); uint16_t GetListenPort(); -struct CombinerAll -{ - typedef bool result_type; - - template<typename I> - bool operator()(I first, I last) const - { - while (first != last) { - if (!(*first)) return false; - ++first; - } - return true; - } -}; - -/** - * Interface for message handling - */ -class NetEventsInterface -{ -public: - virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0; - virtual bool SendMessages(CNode* pnode) = 0; - virtual void InitializeNode(CNode* pnode) = 0; - virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0; - -protected: - /** - * Protected destructor so that instances can only be deleted by derived classes. - * If that restriction is no longer desired, this should be made public and virtual. - */ - ~NetEventsInterface() = default; -}; - enum { LOCAL_NONE, // unknown LOCAL_IF, // address a local interface listens on LOCAL_BIND, // address explicit bound to - LOCAL_UPNP, // address reported by UPnP + LOCAL_MAPPED, // address reported by UPnP or NAT-PMP LOCAL_MANUAL, // address explicitly specified (-externalip=) LOCAL_MAX @@ -650,7 +215,6 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) extern bool fDiscover; extern bool fListen; -extern bool g_relay_txes; /** Subversion as sent to the P2P network in `version` messages */ extern std::string strSubVersion; @@ -682,14 +246,14 @@ public: int nVersion; std::string cleanSubVer; bool fInbound; - bool m_manual_connection; - int nStartingHeight; + bool m_bip152_highbandwidth_to; + bool m_bip152_highbandwidth_from; + int m_starting_height; uint64_t nSendBytes; mapMsgCmdSize mapSendBytesPerMsgCmd; uint64_t nRecvBytes; mapMsgCmdSize mapRecvBytesPerMsgCmd; NetPermissionFlags m_permissionFlags; - bool m_legacyWhitelisted; int64_t m_ping_usec; int64_t m_ping_wait_usec; int64_t m_min_ping_usec; @@ -700,12 +264,13 @@ public: CAddress addr; // Bind address of our side of the connection CAddress addrBind; + // Network the peer connected through + Network m_network; uint32_t m_mapped_as; - std::string m_conn_type_string; + ConnectionType m_conn_type; }; - /** Transport protocol agnostic message container. * Ideally it should only contain receive time, payload, * command and size. @@ -736,8 +301,8 @@ public: virtual bool Complete() const = 0; // set the serialization context version virtual void SetVersion(int version) = 0; - // read and deserialize data - virtual int Read(const char *data, unsigned int bytes) = 0; + /** read and deserialize data, advances msg_bytes data pointer */ + virtual int Read(Span<const uint8_t>& msg_bytes) = 0; // decomposes a message from the context virtual Optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err) = 0; virtual ~TransportDeserializer() {} @@ -758,8 +323,8 @@ private: unsigned int nDataPos; const uint256& GetMessageHash() const; - int readHeader(const char *pch, unsigned int nBytes); - int readData(const char *pch, unsigned int nBytes); + int readHeader(Span<const uint8_t> msg_bytes); + int readData(Span<const uint8_t> msg_bytes); void Reset() { vRecv.clear(); @@ -793,9 +358,14 @@ public: hdrbuf.SetVersion(nVersionIn); vRecv.SetVersion(nVersionIn); } - int Read(const char *pch, unsigned int nBytes) override { - int ret = in_data ? readData(pch, nBytes) : readHeader(pch, nBytes); - if (ret < 0) Reset(); + int Read(Span<const uint8_t>& msg_bytes) override + { + int ret = in_data ? readData(msg_bytes) : readHeader(msg_bytes); + if (ret < 0) { + Reset(); + } else { + msg_bytes = msg_bytes.subspan(ret); + } return ret; } Optional<CNetMessage> GetMessage(std::chrono::microseconds time, uint32_t& out_err_raw_size) override; @@ -825,16 +395,18 @@ public: std::unique_ptr<TransportDeserializer> m_deserializer; std::unique_ptr<TransportSerializer> m_serializer; - // socket + NetPermissionFlags m_permissionFlags{PF_NONE}; std::atomic<ServiceFlags> nServices{NODE_NONE}; SOCKET hSocket GUARDED_BY(cs_hSocket); - size_t nSendSize{0}; // total size of all vSendMsg entries - size_t nSendOffset{0}; // offset inside the first vSendMsg already sent + /** Total size of all vSendMsg entries */ + size_t nSendSize GUARDED_BY(cs_vSend){0}; + /** Offset inside the first vSendMsg already sent */ + size_t nSendOffset GUARDED_BY(cs_vSend){0}; uint64_t nSendBytes GUARDED_BY(cs_vSend){0}; std::deque<std::vector<unsigned char>> vSendMsg GUARDED_BY(cs_vSend); - RecursiveMutex cs_vSend; - RecursiveMutex cs_hSocket; - RecursiveMutex cs_vRecv; + Mutex cs_vSend; + Mutex cs_hSocket; + Mutex cs_vRecv; RecursiveMutex cs_vProcessMsg; std::list<CNetMessage> vProcessMsg GUARDED_BY(cs_vProcessMsg); @@ -842,7 +414,6 @@ public: RecursiveMutex cs_sendProcessing; - std::deque<CInv> vRecvGetData; uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0}; std::atomic<int64_t> nLastSend{0}; @@ -864,10 +435,13 @@ public: bool HasPermission(NetPermissionFlags permission) const { return NetPermissions::HasFlag(m_permissionFlags, permission); } - // This boolean is unusued in actual processing, only present for backward compatibility at RPC/QT level - bool m_legacyWhitelisted{false}; bool fClient{false}; // set by version message bool m_limited_node{false}; //after BIP159, set by version message + /** + * Whether the peer has signaled support for receiving ADDRv2 (BIP155) + * messages, implying a preference to receive ADDRv2 instead of ADDR ones. + */ + std::atomic_bool m_wants_addrv2{false}; std::atomic_bool fSuccessfullyConnected{false}; // Setting fDisconnect to true will cause the node to be disconnected the // next time DisconnectNodes() runs @@ -922,6 +496,9 @@ public: /* Whether we send addr messages over this connection */ bool RelayAddrsWithConn() const { + // Don't relay addr messages to peers that we connect to as block-relay-only + // peers (to prevent adversaries from inferring these links from addr + // traffic). return m_conn_type != ConnectionType::BLOCK_RELAY; } @@ -940,13 +517,22 @@ public: assert(false); } -protected: - mapMsgCmdSize mapSendBytesPerMsgCmd; - mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv); + /** + * Get network the peer connected through. + * + * Returns Network::NET_ONION for *inbound* onion connections, + * and CNetAddr::GetNetClass() otherwise. The latter cannot be used directly + * because it doesn't detect the former, and it's not the responsibility of + * the CNetAddr class to know the actual network a peer is connected through. + * + * @return network the peer connected through. + */ + Network ConnectedThroughNetwork() const; -public: - uint256 hashContinue; - std::atomic<int> nStartingHeight{-1}; + // We selected peer as (compact blocks) high-bandwidth peer (BIP152) + std::atomic<bool> m_bip152_highbandwidth_to{false}; + // Peer selected us as (compact blocks) high-bandwidth peer (BIP152) + std::atomic<bool> m_bip152_highbandwidth_from{false}; // flood relay std::vector<CAddress> vAddrToSend; @@ -955,12 +541,6 @@ public: std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0}; std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0}; - // List of block ids we still have announce. - // There is no final sorting before sending, as they are always sent immediately - // and in the order requested. - std::vector<uint256> vInventoryBlockToSend GUARDED_BY(cs_inventory); - Mutex cs_inventory; - struct TxRelay { mutable RecursiveMutex cs_filter; // We use fRelayTxes for two purposes - @@ -978,12 +558,11 @@ public: // Used for BIP35 mempool sending bool fSendMempool GUARDED_BY(cs_tx_inventory){false}; // Last time a "MEMPOOL" request was serviced. - std::atomic<std::chrono::seconds> m_last_mempool_req{std::chrono::seconds{0}}; + std::atomic<std::chrono::seconds> m_last_mempool_req{0s}; std::chrono::microseconds nNextInvSend{0}; - RecursiveMutex cs_feeFilter; - // Minimum fee rate with which to filter inv's to this node - CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0}; + /** Minimum fee rate with which to filter inv's to this node */ + std::atomic<CAmount> minFeeFilter{0}; CAmount lastSentFeeFilter{0}; int64_t nextSendTimeFeeFilter{0}; }; @@ -991,9 +570,6 @@ public: // m_tx_relay == nullptr if we're not relaying transactions with this peer std::unique_ptr<TxRelay> m_tx_relay; - // Used for headers announcements - unfiltered blocks to relay - std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory); - /** UNIX epoch time of the last block received from this peer that we had * not yet seen (e.g. not already received from another peer), that passed * preliminary validity checks and was saved to disk, even if we don't @@ -1011,7 +587,7 @@ public: // The pong reply we're expecting, or 0 if no pong expected. std::atomic<uint64_t> nPingNonceSent{0}; /** When the last ping was sent, or 0 if no ping was ever sent */ - std::atomic<std::chrono::microseconds> m_ping_start{std::chrono::microseconds{0}}; + std::atomic<std::chrono::microseconds> m_ping_start{0us}; // Last measured round-trip time. std::atomic<int64_t> nPingUsecTime{0}; // Best measured round-trip time. @@ -1019,48 +595,11 @@ public: // Whether a ping is requested. std::atomic<bool> fPingQueued{false}; - std::set<uint256> orphan_work_set; - - 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, ConnectionType conn_type_in); + CNode(NodeId id, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion = false); ~CNode(); CNode(const CNode&) = delete; CNode& operator=(const CNode&) = delete; -private: - const NodeId id; - const uint64_t nLocalHostNonce; - const ConnectionType m_conn_type; - std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION}; - - //! Services offered to this peer. - //! - //! This is supplied by the parent CConnman during peer connection - //! (CConnman::ConnectNode()) from its attribute of the same name. - //! - //! This is const because there is no protocol defined for renegotiating - //! services initially offered to a peer. The set of local services we - //! offer should not change after initialization. - //! - //! An interesting example of this is NODE_NETWORK and initial block - //! download: a node which starts up from scratch doesn't have any blocks - //! to serve, but still advertises NODE_NETWORK because it will eventually - //! fulfill this role after IBD completes. P2P code is written in such a - //! way that it can gracefully handle peers who don't make good on their - //! service advertisements. - const ServiceFlags nLocalServices; - - const int nMyStartingHeight; - NetPermissionFlags m_permissionFlags{ PF_NONE }; - std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread - - mutable RecursiveMutex cs_addrName; - std::string addrName GUARDED_BY(cs_addrName); - - // Our address, as reported by the peer - CService addrLocal GUARDED_BY(cs_addrLocal); - mutable RecursiveMutex cs_addrLocal; -public: - NodeId GetId() const { return id; } @@ -1069,20 +608,26 @@ public: return nLocalHostNonce; } - int GetMyStartingHeight() const { - return nMyStartingHeight; - } - int GetRefCount() const { assert(nRefCount >= 0); return nRefCount; } - bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete); + /** + * Receive bytes from the buffer and deserialize them into messages. + * + * @param[in] msg_bytes The raw data + * @param[out] complete Set True if at least one message has been + * deserialized and is ready to be processed + * @return True if the peer should stay connected, + * False if the peer should be disconnected from. + */ + bool ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete); void SetCommonVersion(int greatest_common_version) { + Assume(m_greatest_common_version == INIT_PROTO_VERSION); m_greatest_common_version = greatest_common_version; } int GetCommonVersion() const @@ -1105,21 +650,29 @@ public: nRefCount--; } - - void AddAddressKnown(const CAddress& _addr) { assert(m_addr_known); m_addr_known->insert(_addr.GetKey()); } + /** + * Whether the peer supports the address. For example, a peer that does not + * implement BIP155 cannot receive Tor v3 addresses because it requires + * ADDRv2 (BIP155) encoding. + */ + bool IsAddrCompatible(const CAddress& addr) const + { + return m_wants_addrv2 || addr.IsAddrV1Compatible(); + } + void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand) { // Known checking here is only to save space from duplicates. // SendMessages will filter it again for knowns that were added // after addresses were pushed. assert(m_addr_known); - if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey())) { + if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey()) && IsAddrCompatible(_addr)) { if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) { vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] = _addr; } else { @@ -1128,7 +681,6 @@ public: } } - void AddKnownTx(const uint256& hash) { if (m_tx_relay != nullptr) { @@ -1159,7 +711,525 @@ public: //! Sets the addrName only if it was not previously set void MaybeSetAddrName(const std::string& addrNameIn); - std::string ConnectionTypeAsString() const; + std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); } + + /** Whether this peer is an inbound onion, e.g. connected via our Tor onion service. */ + bool IsInboundOnion() const { return m_inbound_onion; } + +private: + const NodeId id; + const uint64_t nLocalHostNonce; + const ConnectionType m_conn_type; + std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION}; + + //! Services offered to this peer. + //! + //! This is supplied by the parent CConnman during peer connection + //! (CConnman::ConnectNode()) from its attribute of the same name. + //! + //! This is const because there is no protocol defined for renegotiating + //! services initially offered to a peer. The set of local services we + //! offer should not change after initialization. + //! + //! An interesting example of this is NODE_NETWORK and initial block + //! download: a node which starts up from scratch doesn't have any blocks + //! to serve, but still advertises NODE_NETWORK because it will eventually + //! fulfill this role after IBD completes. P2P code is written in such a + //! way that it can gracefully handle peers who don't make good on their + //! service advertisements. + const ServiceFlags nLocalServices; + + std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread + + mutable RecursiveMutex cs_addrName; + std::string addrName GUARDED_BY(cs_addrName); + + // Our address, as reported by the peer + CService addrLocal GUARDED_BY(cs_addrLocal); + mutable RecursiveMutex cs_addrLocal; + + //! Whether this peer is an inbound onion, e.g. connected via our Tor onion service. + const bool m_inbound_onion{false}; + + mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend); + mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv); +}; + +/** + * Interface for message handling + */ +class NetEventsInterface +{ +public: + /** Initialize a peer (setup state, queue any initial messages) */ + virtual void InitializeNode(CNode* pnode) = 0; + + /** Handle removal of a peer (clear state) */ + virtual void FinalizeNode(const CNode& node, bool& update_connection_time) = 0; + + /** + * Process protocol messages received from a given node + * + * @param[in] pnode The node which we have received messages from. + * @param[in] interrupt Interrupt condition for processing threads + * @return True if there is more work to be done + */ + virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0; + + /** + * Send queued protocol messages to a given node. + * + * @param[in] pnode The node which we are sending messages to. + * @return True if there is more work to be done + */ + virtual bool SendMessages(CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(pnode->cs_sendProcessing) = 0; + + +protected: + /** + * Protected destructor so that instances can only be deleted by derived classes. + * If that restriction is no longer desired, this should be made public and virtual. + */ + ~NetEventsInterface() = default; +}; + +class CConnman +{ +public: + + enum NumConnections { + CONNECTIONS_NONE = 0, + CONNECTIONS_IN = (1U << 0), + CONNECTIONS_OUT = (1U << 1), + CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT), + }; + + struct Options + { + ServiceFlags nLocalServices = NODE_NONE; + int nMaxConnections = 0; + int m_max_outbound_full_relay = 0; + int m_max_outbound_block_relay = 0; + int nMaxAddnode = 0; + int nMaxFeeler = 0; + CClientUIInterface* uiInterface = nullptr; + NetEventsInterface* m_msgproc = nullptr; + BanMan* m_banman = nullptr; + unsigned int nSendBufferMaxSize = 0; + unsigned int nReceiveFloodSize = 0; + uint64_t nMaxOutboundLimit = 0; + int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT; + std::vector<std::string> vSeedNodes; + std::vector<NetWhitelistPermissions> vWhitelistedRange; + std::vector<NetWhitebindPermissions> vWhiteBinds; + std::vector<CService> vBinds; + std::vector<CService> onion_binds; + bool m_use_addrman_outgoing = true; + std::vector<std::string> m_specified_outgoing; + std::vector<std::string> m_added_nodes; + std::vector<bool> m_asmap; + }; + + void Init(const Options& connOptions) { + nLocalServices = connOptions.nLocalServices; + nMaxConnections = connOptions.nMaxConnections; + m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections); + m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay; + m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing; + nMaxAddnode = connOptions.nMaxAddnode; + nMaxFeeler = connOptions.nMaxFeeler; + m_max_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler; + clientInterface = connOptions.uiInterface; + m_banman = connOptions.m_banman; + m_msgproc = connOptions.m_msgproc; + nSendBufferMaxSize = connOptions.nSendBufferMaxSize; + nReceiveFloodSize = connOptions.nReceiveFloodSize; + m_peer_connect_timeout = connOptions.m_peer_connect_timeout; + { + LOCK(cs_totalBytesSent); + nMaxOutboundLimit = connOptions.nMaxOutboundLimit; + } + vWhitelistedRange = connOptions.vWhitelistedRange; + { + LOCK(cs_vAddedNodes); + vAddedNodes = connOptions.m_added_nodes; + } + m_onion_binds = connOptions.onion_binds; + } + + CConnman(uint64_t seed0, uint64_t seed1, bool network_active = true); + ~CConnman(); + bool Start(CScheduler& scheduler, const Options& options); + + void StopThreads(); + void StopNodes(); + void Stop() + { + StopThreads(); + StopNodes(); + }; + + void Interrupt(); + bool GetNetworkActive() const { return fNetworkActive; }; + bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; + void SetNetworkActive(bool active); + void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type); + bool CheckIncomingNonce(uint64_t nonce); + + bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func); + + void PushMessage(CNode* pnode, CSerializedNetMsg&& msg); + + using NodeFn = std::function<void(CNode*)>; + void ForEachNode(const NodeFn& func) + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + func(node); + } + }; + + void ForEachNode(const NodeFn& func) const + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + func(node); + } + }; + + template<typename Callable, typename CallableAfter> + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + pre(node); + } + post(); + }; + + template<typename Callable, typename CallableAfter> + void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const + { + LOCK(cs_vNodes); + for (auto&& node : vNodes) { + if (NodeFullyConnected(node)) + pre(node); + } + post(); + }; + + // Addrman functions + void SetServices(const CService &addr, ServiceFlags nServices); + void MarkAddressGood(const CAddress& addr); + bool AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0); + std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct); + /** + * Cache is used to minimize topology leaks, so it should + * be used for all non-trusted calls, for example, p2p. + * A non-malicious call (from RPC or a peer with addr permission) should + * call the function without a parameter to avoid using the cache. + */ + std::vector<CAddress> GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct); + + // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding + // a peer that is better than all our current peers. + void SetTryNewOutboundPeer(bool flag); + bool GetTryNewOutboundPeer(); + + void StartExtraBlockRelayPeers() { + LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n"); + m_start_extra_block_relay_peers = true; + } + + // Return the number of outbound peers we have in excess of our target (eg, + // if we previously called SetTryNewOutboundPeer(true), and have since set + // to false, we may have extra peers that we wish to disconnect). This may + // return a value less than (num_outbound_connections - num_outbound_slots) + // in cases where some outbound connections are not yet fully connected, or + // not yet fully disconnected. + int GetExtraFullOutboundCount(); + // Count the number of block-relay-only peers we have over our limit. + int GetExtraBlockRelayCount(); + + bool AddNode(const std::string& node); + bool RemoveAddedNode(const std::string& node); + std::vector<AddedNodeInfo> GetAddedNodeInfo(); + + /** + * Attempts to open a connection. Currently only used from tests. + * + * @param[in] address Address of node to try connecting to + * @param[in] conn_type ConnectionType::OUTBOUND or ConnectionType::BLOCK_RELAY + * @return bool Returns false if there are no available + * slots for this connection: + * - conn_type not a supported ConnectionType + * - Max total outbound connection capacity filled + * - Max connection capacity for type is filled + */ + bool AddConnection(const std::string& address, ConnectionType conn_type); + + 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); + + //! Used to convey which local services we are offering peers during node + //! connection. + //! + //! The data returned by this is used in CNode construction, + //! which is used to advertise which services we are offering + //! that peer during `net_processing.cpp:PushNodeVersion()`. + ServiceFlags GetLocalServices() const; + + uint64_t GetMaxOutboundTarget(); + std::chrono::seconds 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 + bool OutboundTargetReached(bool historicalBlockServingLimit); + + //! response the bytes left in the current max outbound cycle + //! in case of no limit, it will always response 0 + uint64_t GetOutboundTargetBytesLeft(); + + //! returns the time left in the current max outbound cycle + //! in case of no limit, it will always return 0 + std::chrono::seconds GetMaxOutboundTimeLeftInCycle(); + + uint64_t GetTotalBytesRecv(); + uint64_t GetTotalBytesSent(); + + /** Get a unique deterministic randomizer. */ + CSipHasher GetDeterministicRandomizer(uint64_t id) const; + + unsigned int GetReceiveFloodSize() const; + + void WakeMessageHandler(); + + /** Attempts to obfuscate tx time through exponentially distributed emitting. + Works assuming that a single interval is used. + Variable intervals will result in privacy decrease. + */ + int64_t PoissonNextSendInbound(int64_t now, int average_interval_seconds); + + void SetAsmap(std::vector<bool> asmap) { addrman.m_asmap = std::move(asmap); } + +private: + struct ListenSocket { + public: + SOCKET socket; + inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); } + ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {} + private: + NetPermissionFlags m_permissions; + }; + + bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions); + bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions); + bool InitBinds( + const std::vector<CService>& binds, + const std::vector<NetWhitebindPermissions>& whiteBinds, + const std::vector<CService>& onion_binds); + + void ThreadOpenAddedConnections(); + void AddAddrFetch(const std::string& strDest); + void ProcessAddrFetch(); + void ThreadOpenConnections(std::vector<std::string> connect); + void ThreadMessageHandler(); + void AcceptConnection(const ListenSocket& hListenSocket); + void DisconnectNodes(); + void NotifyNumConnectionsChanged(); + /** Return true if the peer is inactive and should be disconnected. */ + bool InactivityCheck(const CNode& node) const; + bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set); + void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set); + void SocketHandler(); + void ThreadSocketHandler(); + void ThreadDNSAddressSeed(); + + uint64_t CalculateKeyedNetGroup(const CAddress& ad) const; + + CNode* FindNode(const CNetAddr& ip); + CNode* FindNode(const CSubNet& subNet); + CNode* FindNode(const std::string& addrName); + CNode* FindNode(const CService& addr); + + /** + * Determine whether we're already connected to a given address, in order to + * avoid initiating duplicate connections. + */ + bool AlreadyConnectedToAddress(const CAddress& addr); + + bool AttemptToEvictConnection(); + CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type); + void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const; + + void DeleteNode(CNode* pnode); + + NodeId GetNewNodeId(); + + size_t SocketSendData(CNode& node) const EXCLUSIVE_LOCKS_REQUIRED(node.cs_vSend); + void DumpAddresses(); + + // Network stats + void RecordBytesRecv(uint64_t bytes); + void RecordBytesSent(uint64_t bytes); + + /** + * Return vector of current BLOCK_RELAY peers. + */ + std::vector<CAddress> GetCurrentBlockRelayOnlyConns() const; + + // Whether the node should be passed out in ForEach* callbacks + static bool NodeFullyConnected(const CNode* pnode); + + // Network usage totals + RecursiveMutex cs_totalBytesRecv; + RecursiveMutex cs_totalBytesSent; + uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0}; + uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0}; + + // outbound limit & stats + uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent) {0}; + std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent) {0}; + uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent); + + // P2P timeout in seconds + int64_t m_peer_connect_timeout; + + // Whitelisted ranges. Any node connecting from these is automatically + // whitelisted (as well as those connecting to whitelisted binds). + std::vector<NetWhitelistPermissions> vWhitelistedRange; + + unsigned int nSendBufferMaxSize{0}; + unsigned int nReceiveFloodSize{0}; + + std::vector<ListenSocket> vhListenSocket; + std::atomic<bool> fNetworkActive{true}; + bool fAddressesInitialized{false}; + CAddrMan addrman; + std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex); + RecursiveMutex m_addr_fetches_mutex; + std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes); + RecursiveMutex cs_vAddedNodes; + std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes); + std::list<CNode*> vNodesDisconnected; + mutable RecursiveMutex cs_vNodes; + std::atomic<NodeId> nLastNodeId{0}; + unsigned int nPrevNodeCount{0}; + + /** + * Cache responses to addr requests to minimize privacy leak. + * Attack example: scraping addrs in real-time may allow an attacker + * to infer new connections of the victim by detecting new records + * with fresh timestamps (per self-announcement). + */ + struct CachedAddrResponse { + std::vector<CAddress> m_addrs_response_cache; + std::chrono::microseconds m_cache_entry_expiration{0}; + }; + + /** + * Addr responses stored in different caches + * per (network, local socket) prevent cross-network node identification. + * If a node for example is multi-homed under Tor and IPv6, + * a single cache (or no cache at all) would let an attacker + * to easily detect that it is the same node by comparing responses. + * Indexing by local socket prevents leakage when a node has multiple + * listening addresses on the same network. + * + * The used memory equals to 1000 CAddress records (or around 40 bytes) per + * distinct Network (up to 5) we have/had an inbound peer from, + * resulting in at most ~196 KB. Every separate local socket may + * add up to ~196 KB extra. + */ + std::map<uint64_t, CachedAddrResponse> m_addr_response_caches; + + /** + * Services this instance offers. + * + * This data is replicated in each CNode instance we create during peer + * connection (in ConnectNode()) under a member also called + * nLocalServices. + * + * This data is not marked const, but after being set it should not + * change. See the note in CNode::nLocalServices documentation. + * + * \sa CNode::nLocalServices + */ + ServiceFlags nLocalServices; + + std::unique_ptr<CSemaphore> semOutbound; + std::unique_ptr<CSemaphore> semAddnode; + int nMaxConnections; + + // How many full-relay (tx, block, addr) outbound peers we want + int m_max_outbound_full_relay; + + // How many block-relay only outbound peers we want + // We do not relay tx or addr messages with these peers + int m_max_outbound_block_relay; + + int nMaxAddnode; + int nMaxFeeler; + int m_max_outbound; + bool m_use_addrman_outgoing; + CClientUIInterface* clientInterface; + NetEventsInterface* m_msgproc; + /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */ + BanMan* m_banman; + + /** + * Addresses that were saved during the previous clean shutdown. We'll + * attempt to make block-relay-only connections to them. + */ + std::vector<CAddress> m_anchors; + + /** SipHasher seeds for deterministic randomness */ + const uint64_t nSeed0, nSeed1; + + /** flag for waking the message processor. */ + bool fMsgProcWake GUARDED_BY(mutexMsgProc); + + std::condition_variable condMsgProc; + Mutex mutexMsgProc; + std::atomic<bool> flagInterruptMsgProc{false}; + + CThreadInterrupt interruptNet; + + std::thread threadDNSAddressSeed; + std::thread threadSocketHandler; + std::thread threadOpenAddedConnections; + std::thread threadOpenConnections; + std::thread threadMessageHandler; + + /** flag for deciding to connect to an extra outbound peer, + * in excess of m_max_outbound_full_relay + * This takes the place of a feeler connection */ + std::atomic_bool m_try_another_outbound_peer; + + /** flag for initiating extra block-relay-only peer connections. + * this should only be enabled after initial chain sync has occurred, + * as these connections are intended to be short-lived and low-bandwidth. + */ + std::atomic_bool m_start_extra_block_relay_peers{false}; + + std::atomic<int64_t> m_next_send_inv_to_incoming{0}; + + /** + * A vector of -bind=<address>:<port>=onion arguments each of which is + * an address and port that are designated for incoming Tor connections. + */ + std::vector<CService> m_onion_binds; + + friend struct CConnmanTest; + friend struct ConnmanTestMsg; }; /** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ @@ -1171,4 +1241,21 @@ inline std::chrono::microseconds PoissonNextSend(std::chrono::microseconds now, return std::chrono::microseconds{PoissonNextSend(now.count(), average_interval.count())}; } +struct NodeEvictionCandidate +{ + NodeId id; + int64_t nTimeConnected; + int64_t nMinPingUsecTime; + int64_t nLastBlockTime; + int64_t nLastTXTime; + bool fRelevantServices; + bool fRelayTxes; + bool fBloomFilter; + uint64_t nKeyedNetGroup; + bool prefer_evict; + bool m_is_local; +}; + +[[nodiscard]] Optional<NodeId> SelectNodeToEvict(std::vector<NodeEvictionCandidate>&& vEvictionCandidates); + #endif // BITCOIN_NET_H diff --git a/src/net_permissions.cpp b/src/net_permissions.cpp index 53648deb40..1fdcd97593 100644 --- a/src/net_permissions.cpp +++ b/src/net_permissions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,7 +12,7 @@ const std::vector<std::string> NET_PERMISSIONS_DOC{ "bloomfilter (allow requesting BIP37 filtered blocks and transactions)", "noban (do not ban for misbehavior; implies download)", "forcerelay (relay transactions that are already in the mempool; implies relay)", - "relay (relay even in -blocksonly mode)", + "relay (relay even in -blocksonly mode, and unlimited transaction announcements)", "mempool (allow requesting BIP35 mempool contents)", "download (allow getheaders during IBD, no disconnect after maxuploadtarget limit)", "addr (responses to GETADDR avoid hitting the cache and contain random records with the most up-to-date info)" diff --git a/src/net_permissions.h b/src/net_permissions.h index 5b68f635a7..bba0ea1695 100644 --- a/src/net_permissions.h +++ b/src/net_permissions.h @@ -19,6 +19,7 @@ enum NetPermissionFlags { // Can query bloomfilter even if -peerbloomfilters is false PF_BLOOMFILTER = (1U << 1), // Relay and accept transactions from this peer, even if -blocksonly is true + // This peer is also not subject to limits on how many transaction INVs are tracked PF_RELAY = (1U << 3), // Always relay transactions from this peer, even if already in mempool // Keep parameter interaction: forcerelay implies relay diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f784a9b754..a4070f5b63 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -23,8 +23,10 @@ #include <random.h> #include <reverse_iterator.h> #include <scheduler.h> +#include <streams.h> #include <tinyformat.h> #include <txmempool.h> +#include <txrequest.h> #include <util/check.h> // For NDEBUG compile time check #include <util/strencodings.h> #include <util/system.h> @@ -71,22 +73,22 @@ static constexpr std::chrono::minutes PING_INTERVAL{2}; static const unsigned int MAX_LOCATOR_SZ = 101; /** The maximum number of entries in an 'inv' protocol message */ static const unsigned int MAX_INV_SZ = 50000; -/** Maximum number of in-flight transactions from a peer */ -static constexpr int32_t MAX_PEER_TX_IN_FLIGHT = 100; -/** Maximum number of announced transactions from a peer */ -static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 2 * MAX_INV_SZ; -/** How many microseconds to delay requesting transactions via txids, if we have wtxid-relaying peers */ -static constexpr std::chrono::microseconds TXID_RELAY_DELAY{std::chrono::seconds{2}}; -/** How many microseconds to delay requesting transactions from inbound peers */ -static constexpr std::chrono::microseconds INBOUND_PEER_TX_DELAY{std::chrono::seconds{2}}; +/** Maximum number of in-flight transaction requests from a peer. It is not a hard limit, but the threshold at which + * point the OVERLOADED_PEER_TX_DELAY kicks in. */ +static constexpr int32_t MAX_PEER_TX_REQUEST_IN_FLIGHT = 100; +/** Maximum number of transactions to consider for requesting, per peer. It provides a reasonable DoS limit to + * per-peer memory usage spent on announcements, while covering peers continuously sending INVs at the maximum + * rate (by our own policy, see INVENTORY_BROADCAST_PER_SECOND) for several minutes, while not receiving + * the actual transaction (from any peer) in response to requests for them. */ +static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 5000; +/** How long to delay requesting transactions via txids, if we have wtxid-relaying peers */ +static constexpr auto TXID_RELAY_DELAY = std::chrono::seconds{2}; +/** How long to delay requesting transactions from non-preferred peers */ +static constexpr auto NONPREF_PEER_TX_DELAY = std::chrono::seconds{2}; +/** How long to delay requesting transactions from overloaded peers (see MAX_PEER_TX_REQUEST_IN_FLIGHT). */ +static constexpr auto OVERLOADED_PEER_TX_DELAY = std::chrono::seconds{2}; /** How long to wait (in microseconds) before downloading a transaction from an additional peer */ static constexpr std::chrono::microseconds GETDATA_TX_INTERVAL{std::chrono::seconds{60}}; -/** Maximum delay (in microseconds) for transaction requests to avoid biasing some peers over others. */ -static constexpr std::chrono::microseconds MAX_GETDATA_RANDOM_DELAY{std::chrono::seconds{2}}; -/** How long to wait (in microseconds) before expiring an in-flight getdata request to a peer */ -static constexpr std::chrono::microseconds TX_EXPIRY_INTERVAL{GETDATA_TX_INTERVAL * 10}; -static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY, -"To preserve security, MAX_GETDATA_RANDOM_DELAY should not exceed INBOUND_PEER_DELAY"); /** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */ static const unsigned int MAX_GETDATA_SZ = 1000; /** Number of blocks that can be requested at any given time from a single peer. */ @@ -153,14 +155,200 @@ struct COrphanTx { int64_t nTimeExpire; size_t list_pos; }; + +/** Guards orphan transactions and extra txs for compact blocks */ RecursiveMutex g_cs_orphans; +/** Map from txid to orphan transaction record. Limited by + * -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */ std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); +/** Index from wtxid into the mapOrphanTransactions to lookup orphan + * transactions using their witness ids. */ std::map<uint256, std::map<uint256, COrphanTx>::iterator> g_orphans_by_wtxid GUARDED_BY(g_cs_orphans); void EraseOrphansFor(NodeId peer); // Internal stuff namespace { +/** + * Data structure for an individual peer. This struct is not protected by + * cs_main since it does not contain validation-critical data. + * + * Memory is owned by shared pointers and this object is destructed when + * the refcount drops to zero. + * + * Mutexes inside this struct must not be held when locking m_peer_mutex. + * + * TODO: move most members from CNodeState to this structure. + * TODO: move remaining application-layer data members from CNode to this structure. + */ +struct Peer { + /** Same id as the CNode object for this peer */ + const NodeId m_id{0}; + + /** Protects misbehavior data members */ + Mutex m_misbehavior_mutex; + /** Accumulated misbehavior score for this peer */ + int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0}; + /** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */ + bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false}; + + /** Protects block inventory data members */ + Mutex m_block_inv_mutex; + /** List of blocks that we'll announce via an `inv` message. + * There is no final sorting before sending, as they are always sent + * immediately and in the order requested. */ + std::vector<uint256> m_blocks_for_inv_relay GUARDED_BY(m_block_inv_mutex); + /** Unfiltered list of blocks that we'd like to announce via a `headers` + * message. If we can't announce via a `headers` message, we'll fall back to + * announcing via `inv`. */ + std::vector<uint256> m_blocks_for_headers_relay GUARDED_BY(m_block_inv_mutex); + /** The final block hash that we sent in an `inv` message to this peer. + * When the peer requests this block, we send an `inv` message to trigger + * the peer to request the next sequence of block hashes. + * Most peers use headers-first syncing, which doesn't use this mechanism */ + uint256 m_continuation_block GUARDED_BY(m_block_inv_mutex) {}; + + /** This peer's reported block height when we connected */ + std::atomic<int> m_starting_height{-1}; + + /** Set of txids to reconsider once their parent transactions have been accepted **/ + std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans); + + /** Protects m_getdata_requests **/ + Mutex m_getdata_requests_mutex; + /** Work queue of items requested by this peer **/ + std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex); + + explicit Peer(NodeId id) : m_id(id) {} +}; + +using PeerRef = std::shared_ptr<Peer>; + +class PeerManagerImpl final : public PeerManager +{ +public: + PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, BanMan* banman, + CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool, + bool ignore_incoming_txs); + + /** Overridden from CValidationInterface. */ + void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override; + void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override; + void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; + void BlockChecked(const CBlock& block, const BlockValidationState& state) override; + void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override; + + /** Implement NetEventsInterface */ + void InitializeNode(CNode* pnode) override; + void FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) override; + bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override; + bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing); + + /** Implement PeerManager */ + void CheckForStaleTipAndEvictPeers() override; + bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) override; + bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; } + void SetBestHeight(int height) override { m_best_height = height; }; + void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override; + void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, + const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override; + +private: + /** Consider evicting an outbound peer based on the amount of time they've been behind our tip */ + void ConsiderEviction(CNode& pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */ + void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + /** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */ + void ReattemptInitialBroadcast(CScheduler& scheduler) const; + + /** Get a shared pointer to the Peer object. + * May return an empty shared_ptr if the Peer object can't be found. */ + PeerRef GetPeerRef(NodeId id) const; + + /** Get a shared pointer to the Peer object and remove it from m_peer_map. + * May return an empty shared_ptr if the Peer object can't be found. */ + PeerRef RemovePeer(NodeId id); + + /** + * Potentially mark a node discouraged based on the contents of a BlockValidationState object + * + * @param[in] via_compact_block this bool is passed in because net_processing should + * punish peers differently depending on whether the data was provided in a compact + * block message or not. If the compact block had a valid header, but contained invalid + * txs, the peer should not be punished. See BIP 152. + * + * @return Returns true if the peer was punished (probably disconnected) + */ + bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, + bool via_compact_block, const std::string& message = ""); + + /** + * Potentially disconnect and discourage a node based on the contents of a TxValidationState object + * + * @return Returns true if the peer was punished (probably disconnected) + */ + bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = ""); + + /** Maybe disconnect a peer and discourage future connections from its address. + * + * @param[in] pnode The node to check. + * @return True if the peer was marked for disconnection in this function + */ + bool MaybeDiscourageAndDisconnect(CNode& pnode); + + void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans); + /** Process a single headers message from a peer. */ + void ProcessHeadersMessage(CNode& pfrom, const Peer& peer, + const std::vector<CBlockHeader>& headers, + bool via_compact_block); + + void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req); + + /** Register with TxRequestTracker that an INV has been received from a + * peer. The announcement parameters are decided in PeerManager and then + * passed to TxRequestTracker. */ + void AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + + /** Send a version message to a peer */ + void PushNodeVersion(CNode& pnode, int64_t nTime); + + const CChainParams& m_chainparams; + CConnman& m_connman; + /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */ + BanMan* const m_banman; + ChainstateManager& m_chainman; + CTxMemPool& m_mempool; + TxRequestTracker m_txrequest GUARDED_BY(::cs_main); + + /** The height of the best chain */ + std::atomic<int> m_best_height{-1}; + + int64_t m_stale_tip_check_time; //!< Next time to check for stale tip + + /** Whether this node is running in blocks only mode */ + const bool m_ignore_incoming_txs; + + /** Whether we've completed initial sync yet, for determining when to turn + * on extra block-relay-only peers. */ + bool m_initial_sync_finished{false}; + + /** Protects m_peer_map. This mutex must not be locked while holding a lock + * on any of the mutexes inside a Peer object. */ + mutable Mutex m_peer_mutex; + /** + * Map of all Peer objects, keyed by peer id. This map is protected + * by the m_peer_mutex. Once a shared pointer reference is + * taken, the lock may be released. Individual fields are protected by + * their own locks. + */ + std::map<NodeId, PeerRef> m_peer_map GUARDED_BY(m_peer_mutex); +}; +} // namespace + +namespace { /** Number of nodes with fSyncStarted. */ int nSyncStarted GUARDED_BY(cs_main) = 0; @@ -258,12 +446,19 @@ namespace { return &(*a) < &(*b); } }; - std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans); - std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY(g_cs_orphans); //! For random eviction + /** Index from the parents' COutPoint into the mapOrphanTransactions. Used + * to remove orphan transactions from the mapOrphanTransactions */ + std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans); + /** Orphan transactions in vector for quick random eviction */ + std::vector<std::map<uint256, COrphanTx>::iterator> g_orphan_list GUARDED_BY(g_cs_orphans); - static size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; + /** Orphan/conflicted/etc transactions that are kept for compact block reconstruction. + * The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of + * these are kept in a ring buffer */ static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans); + /** Offset into vExtraTxnForCompact to insert the next tx */ + static size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; } // namespace namespace { @@ -276,8 +471,6 @@ namespace { struct CNodeState { //! The peer's address const CService address; - //! Whether we have a fully established connection. - bool fCurrentlyConnected; //! The best known block we know this peer has announced. const CBlockIndex *pindexBestKnownBlock; //! The hash of the last unknown block this peer has announced. @@ -321,10 +514,17 @@ struct CNodeState { */ bool fSupportsDesiredCmpctVersion; - /** State used to enforce CHAIN_SYNC_TIMEOUT - * Only in effect for outbound, non-manual, full-relay connections, with - * m_protect == false - * Algorithm: if a peer's best known block has less work than our tip, + /** State used to enforce CHAIN_SYNC_TIMEOUT and EXTRA_PEER_CHECK_INTERVAL logic. + * + * Both are only in effect for outbound, non-manual, non-protected connections. + * Any peer protected (m_protect = true) is not chosen for eviction. A peer is + * marked as protected if all of these are true: + * - its connection type is IsBlockOnlyConn() == false + * - it gave us a valid connecting header + * - we haven't reached MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT yet + * - it has a better chain than we have + * + * CHAIN_SYNC_TIMEOUT: if a peer's best known block has less work than our tip, * set a timeout CHAIN_SYNC_TIMEOUT seconds in the future: * - If at timeout their best known block now has more work than our tip * when the timeout was set, then either reset the timeout or clear it @@ -334,6 +534,9 @@ struct CNodeState { * and set a shorter timeout, HEADERS_RESPONSE_TIME seconds in future. * If their best known block is still behind when that new timeout is * reached, disconnect. + * + * EXTRA_PEER_CHECK_INTERVAL: after each interval, if we have too many outbound peers, + * drop the outbound one that least recently announced us a new block. */ struct ChainSyncTimeoutState { //! A timeout used for checking whether our peer has sufficiently synced @@ -351,85 +554,18 @@ struct CNodeState { //! Time of last new block announcement int64_t m_last_block_announcement; - /* - * State associated with transaction download. - * - * Tx download algorithm: - * - * When inv comes in, queue up (process_time, txid) inside the peer's - * CNodeState (m_tx_process_time) as long as m_tx_announced for the peer - * isn't too big (MAX_PEER_TX_ANNOUNCEMENTS). - * - * The process_time for a transaction is set to nNow for outbound peers, - * nNow + 2 seconds for inbound peers. This is the time at which we'll - * consider trying to request the transaction from the peer in - * SendMessages(). The delay for inbound peers is to allow outbound peers - * a chance to announce before we request from inbound peers, to prevent - * an adversary from using inbound connections to blind us to a - * transaction (InvBlock). - * - * When we call SendMessages() for a given peer, - * we will loop over the transactions in m_tx_process_time, looking - * at the transactions whose process_time <= nNow. We'll request each - * such transaction that we don't have already and that hasn't been - * requested from another peer recently, up until we hit the - * MAX_PEER_TX_IN_FLIGHT limit for the peer. Then we'll update - * g_already_asked_for for each requested txid, storing the time of the - * GETDATA request. We use g_already_asked_for to coordinate transaction - * requests amongst our peers. - * - * For transactions that we still need but we have already recently - * requested from some other peer, we'll reinsert (process_time, txid) - * back into the peer's m_tx_process_time at the point in the future at - * which the most recent GETDATA request would time out (ie - * GETDATA_TX_INTERVAL + the request time stored in g_already_asked_for). - * We add an additional delay for inbound peers, again to prefer - * attempting download from outbound peers first. - * We also add an extra small random delay up to 2 seconds - * to avoid biasing some peers over others. (e.g., due to fixed ordering - * of peer processing in ThreadMessageHandler). - * - * When we receive a transaction from a peer, we remove the txid from the - * peer's m_tx_in_flight set and from their recently announced set - * (m_tx_announced). We also clear g_already_asked_for for that entry, so - * that if somehow the transaction is not accepted but also not added to - * the reject filter, then we will eventually redownload from other - * peers. - */ - struct TxDownloadState { - /* Track when to attempt download of announced transactions (process - * time in micros -> txid) - */ - std::multimap<std::chrono::microseconds, GenTxid> m_tx_process_time; - - //! Store all the transactions a peer has recently announced - std::set<uint256> m_tx_announced; - - //! Store transactions which were requested by us, with timestamp - std::map<uint256, std::chrono::microseconds> m_tx_in_flight; - - //! Periodically check for stuck getdata requests - std::chrono::microseconds m_check_expiry_timer{0}; - }; - - TxDownloadState m_tx_download; - //! Whether this peer is an inbound connection bool m_is_inbound; - //! Whether this peer is a manual connection - bool m_is_manual_connection; - //! A rolling bloom filter of all announced tx CInvs to this peer. CRollingBloomFilter m_recently_announced_invs = CRollingBloomFilter{INVENTORY_MAX_RECENT_RELAY, 0.000001}; //! Whether this peer relays txs via wtxid bool m_wtxid_relay{false}; - CNodeState(CAddress addrIn, bool is_inbound, bool is_manual) - : address(addrIn), m_is_inbound(is_inbound), m_is_manual_connection(is_manual) + CNodeState(CAddress addrIn, bool is_inbound) + : address(addrIn), m_is_inbound(is_inbound) { - fCurrentlyConnected = false; pindexBestKnownBlock = nullptr; hashLastUnknownBlock.SetNull(); pindexLastCommonBlock = nullptr; @@ -454,9 +590,6 @@ struct CNodeState { } }; -// Keeps track of the time (in microseconds) when transactions were requested last time -limitedmap<uint256, std::chrono::microseconds> g_already_asked_for GUARDED_BY(cs_main)(MAX_INV_SZ); - /** Map maintaining per-node state. */ static std::map<NodeId, CNodeState> mapNodeState GUARDED_BY(cs_main); @@ -467,50 +600,6 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return &it->second; } -/** - * Data structure for an individual peer. This struct is not protected by - * cs_main since it does not contain validation-critical data. - * - * Memory is owned by shared pointers and this object is destructed when - * the refcount drops to zero. - * - * TODO: move most members from CNodeState to this structure. - * TODO: move remaining application-layer data members from CNode to this structure. - */ -struct Peer { - /** Same id as the CNode object for this peer */ - const NodeId m_id{0}; - - /** Protects misbehavior data members */ - Mutex m_misbehavior_mutex; - /** Accumulated misbehavior score for this peer */ - int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0}; - /** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */ - bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false}; - - Peer(NodeId id) : m_id(id) {} -}; - -using PeerRef = std::shared_ptr<Peer>; - -/** - * Map of all Peer objects, keyed by peer id. This map is protected - * by the global g_peer_mutex. Once a shared pointer reference is - * taken, the lock may be released. Individual fields are protected by - * their own locks. - */ -Mutex g_peer_mutex; -static std::map<NodeId, PeerRef> g_peer_map GUARDED_BY(g_peer_mutex); - -/** Get a shared pointer to the Peer object. - * May return nullptr if the Peer object can't be found. */ -static PeerRef GetPeerRef(NodeId id) -{ - LOCK(g_peer_mutex); - auto it = g_peer_map.find(id); - return it != g_peer_map.end() ? it->second : nullptr; -} - static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { nPreferredDownload -= state->fPreferredDownload; @@ -521,30 +610,6 @@ static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUS nPreferredDownload += state->fPreferredDownload; } -static void PushNodeVersion(CNode& pnode, CConnman& connman, int64_t nTime) -{ - // Note that pnode->GetLocalServices() is a reflection of the local - // services we were offering when the CNode object was created for this - // peer. - ServiceFlags nLocalNodeServices = pnode.GetLocalServices(); - uint64_t nonce = pnode.GetLocalNonce(); - int nNodeStartingHeight = pnode.GetMyStartingHeight(); - NodeId nodeid = pnode.GetId(); - CAddress addr = pnode.addr; - - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices)); - CAddress addrMe = CAddress(CService(), nLocalNodeServices); - - connman.PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, - nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes && pnode.m_tx_relay != nullptr)); - - if (fLogIPs) { - LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); - } else { - LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid); - } -} - // Returns a bool indicating whether we requested this block. // Also used if a block was /not/ received and timed out or started with another peer static bool MarkBlockAsReceived(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { @@ -559,7 +624,7 @@ static bool MarkBlockAsReceived(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs } if (state->vBlocksInFlight.begin() == itInFlight->second.second) { // First block on the queue was received, update the start download time for the next one - state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros()); + state->nDownloadingSince = std::max(state->nDownloadingSince, count_microseconds(GetTime<std::chrono::microseconds>())); } state->vBlocksInFlight.erase(itInFlight->second.second); state->nBlocksInFlight--; @@ -594,7 +659,7 @@ static bool MarkBlockAsInFlight(CTxMemPool& mempool, NodeId nodeid, const uint25 state->nBlocksInFlightValidHeaders += it->fValidatedHeaders; if (state->nBlocksInFlight == 1) { // We're starting a block download (batch) from this peer. - state->nDownloadingSince = GetTimeMicros(); + state->nDownloadingSince = GetTime<std::chrono::microseconds>().count(); } if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr) { nPeersWithValidatedDownloads++; @@ -670,11 +735,15 @@ static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connma // blocks using compact encodings. connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, nCMPCTBLOCKVersion](CNode* pnodeStop){ connman.PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/false, nCMPCTBLOCKVersion)); + // save BIP152 bandwidth state: we select peer to be low-bandwidth + pnodeStop->m_bip152_highbandwidth_to = false; return true; }); lNodesAnnouncingHeaderAndIDs.pop_front(); } connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetCommonVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/true, nCMPCTBLOCKVersion)); + // save BIP152 bandwidth state: we select peer to be high-bandwidth + pfrom->m_bip152_highbandwidth_to = true; lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); return true; }); @@ -793,73 +862,62 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec } } -void EraseTxRequest(const GenTxid& gtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - g_already_asked_for.erase(gtxid.GetHash()); -} +} // namespace -std::chrono::microseconds GetTxRequestTime(const GenTxid& gtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +void PeerManagerImpl::PushNodeVersion(CNode& pnode, int64_t nTime) { - auto it = g_already_asked_for.find(gtxid.GetHash()); - if (it != g_already_asked_for.end()) { - return it->second; - } - return {}; -} + // Note that pnode->GetLocalServices() is a reflection of the local + // services we were offering when the CNode object was created for this + // peer. + ServiceFlags nLocalNodeServices = pnode.GetLocalServices(); + uint64_t nonce = pnode.GetLocalNonce(); + const int nNodeStartingHeight{m_best_height}; + NodeId nodeid = pnode.GetId(); + CAddress addr = pnode.addr; -void UpdateTxRequestTime(const GenTxid& gtxid, std::chrono::microseconds request_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - auto it = g_already_asked_for.find(gtxid.GetHash()); - if (it == g_already_asked_for.end()) { - g_already_asked_for.insert(std::make_pair(gtxid.GetHash(), request_time)); - } else { - g_already_asked_for.update(it, request_time); - } -} + CAddress addrYou = addr.IsRoutable() && !IsProxy(addr) && addr.IsAddrV1Compatible() ? + addr : + CAddress(CService(), addr.nServices); + CAddress addrMe = CAddress(CService(), nLocalNodeServices); -std::chrono::microseconds CalculateTxGetDataTime(const GenTxid& gtxid, std::chrono::microseconds current_time, bool use_inbound_delay, bool use_txid_delay) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - std::chrono::microseconds process_time; - const auto last_request_time = GetTxRequestTime(gtxid); - // First time requesting this tx - if (last_request_time.count() == 0) { - process_time = current_time; + const bool tx_relay = !m_ignore_incoming_txs && pnode.m_tx_relay != nullptr; + m_connman.PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, + nonce, strSubVersion, nNodeStartingHeight, tx_relay)); + + if (fLogIPs) { + LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), tx_relay, nodeid); } else { - // Randomize the delay to avoid biasing some peers over others (such as due to - // fixed ordering of peer processing in ThreadMessageHandler) - process_time = last_request_time + GETDATA_TX_INTERVAL + GetRandMicros(MAX_GETDATA_RANDOM_DELAY); + LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), tx_relay, nodeid); } - - // We delay processing announcements from inbound peers - if (use_inbound_delay) process_time += INBOUND_PEER_TX_DELAY; - - // We delay processing announcements from peers that use txid-relay (instead of wtxid) - if (use_txid_delay) process_time += TXID_RELAY_DELAY; - - return process_time; } -void RequestTx(CNodeState* state, const GenTxid& gtxid, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +void PeerManagerImpl::AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time) { - CNodeState::TxDownloadState& peer_download_state = state->m_tx_download; - if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS || - peer_download_state.m_tx_process_time.size() >= MAX_PEER_TX_ANNOUNCEMENTS || - peer_download_state.m_tx_announced.count(gtxid.GetHash())) { - // Too many queued announcements from this peer, or we already have - // this announcement + AssertLockHeld(::cs_main); // For m_txrequest + NodeId nodeid = node.GetId(); + if (!node.HasPermission(PF_RELAY) && m_txrequest.Count(nodeid) >= MAX_PEER_TX_ANNOUNCEMENTS) { + // Too many queued announcements from this peer return; } - peer_download_state.m_tx_announced.insert(gtxid.GetHash()); - - // Calculate the time to try requesting this transaction. Use - // fPreferredDownload as a proxy for outbound peers. - const auto process_time = CalculateTxGetDataTime(gtxid, current_time, !state->fPreferredDownload, !state->m_wtxid_relay && g_wtxid_relay_peers > 0); - - peer_download_state.m_tx_process_time.emplace(process_time, gtxid); + const CNodeState* state = State(nodeid); + + // Decide the TxRequestTracker parameters for this announcement: + // - "preferred": if fPreferredDownload is set (= outbound, or PF_NOBAN permission) + // - "reqtime": current time plus delays for: + // - NONPREF_PEER_TX_DELAY for announcements from non-preferred connections + // - TXID_RELAY_DELAY for txid announcements while wtxid peers are available + // - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least + // MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have PF_RELAY). + auto delay = std::chrono::microseconds{0}; + const bool preferred = state->fPreferredDownload; + if (!preferred) delay += NONPREF_PEER_TX_DELAY; + if (!gtxid.IsWtxid() && g_wtxid_relay_peers > 0) delay += TXID_RELAY_DELAY; + const bool overloaded = !node.HasPermission(PF_RELAY) && + m_txrequest.CountInFlight(nodeid) >= MAX_PEER_TX_REQUEST_IN_FLIGHT; + if (overloaded) delay += OVERLOADED_PEER_TX_DELAY; + m_txrequest.ReceivedInv(nodeid, gtxid, preferred, current_time + delay); } -} // namespace - // This function is used for testing the stale tip eviction logic, see // denialofservice_tests.cpp void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) @@ -869,25 +927,27 @@ void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) if (state) state->m_last_block_announcement = time_in_seconds; } -void PeerManager::InitializeNode(CNode *pnode) { +void PeerManagerImpl::InitializeNode(CNode *pnode) +{ CAddress addr = pnode->addr; std::string addrName = pnode->GetAddrName(); NodeId nodeid = pnode->GetId(); { LOCK(cs_main); - mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, pnode->IsInboundConn(), pnode->IsManualConn())); + mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, pnode->IsInboundConn())); + assert(m_txrequest.Count(nodeid) == 0); } { PeerRef peer = std::make_shared<Peer>(nodeid); - LOCK(g_peer_mutex); - g_peer_map.emplace_hint(g_peer_map.end(), nodeid, std::move(peer)); + LOCK(m_peer_mutex); + m_peer_map.emplace_hint(m_peer_map.end(), nodeid, std::move(peer)); } if (!pnode->IsInboundConn()) { - PushNodeVersion(*pnode, m_connman, GetTime()); + PushNodeVersion(*pnode, GetTime()); } } -void PeerManager::ReattemptInitialBroadcast(CScheduler& scheduler) const +void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) const { std::set<uint256> unbroadcast_txids = m_mempool.GetUnbroadcastTxs(); @@ -908,16 +968,21 @@ void PeerManager::ReattemptInitialBroadcast(CScheduler& scheduler) const scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } -void PeerManager::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { +void PeerManagerImpl::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) +{ + NodeId nodeid = node.GetId(); fUpdateConnectionTime = false; LOCK(cs_main); int misbehavior{0}; { - PeerRef peer = GetPeerRef(nodeid); + // We remove the PeerRef from g_peer_map here, but we don't always + // destruct the Peer. Sometimes another thread is still holding a + // PeerRef, so the refcount is >= 1. Be careful not to do any + // processing here that assumes Peer won't be changed before it's + // destructed. + PeerRef peer = RemovePeer(nodeid); assert(peer != nullptr); misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score); - LOCK(g_peer_mutex); - g_peer_map.erase(nodeid); } CNodeState *state = State(nodeid); assert(state != nullptr); @@ -925,7 +990,9 @@ void PeerManager::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { if (state->fSyncStarted) nSyncStarted--; - if (misbehavior == 0 && state->fCurrentlyConnected) { + if (node.fSuccessfullyConnected && misbehavior == 0 && + !node.IsBlockOnlyConn() && !node.IsInboundConn()) { + // Only change visible addrman state for outbound, full-relay peers fUpdateConnectionTime = true; } @@ -933,6 +1000,7 @@ void PeerManager::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { mapBlocksInFlight.erase(entry.hash); } EraseOrphansFor(nodeid); + m_txrequest.DisconnectedPeer(nodeid); nPreferredDownload -= state->fPreferredDownload; nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); assert(nPeersWithValidatedDownloads >= 0); @@ -950,11 +1018,32 @@ void PeerManager::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { assert(nPeersWithValidatedDownloads == 0); assert(g_outbound_peers_with_protect_from_disconnect == 0); assert(g_wtxid_relay_peers == 0); + assert(m_txrequest.Size() == 0); } LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); } -bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { +PeerRef PeerManagerImpl::GetPeerRef(NodeId id) const +{ + LOCK(m_peer_mutex); + auto it = m_peer_map.find(id); + return it != m_peer_map.end() ? it->second : nullptr; +} + +PeerRef PeerManagerImpl::RemovePeer(NodeId id) +{ + PeerRef ret; + LOCK(m_peer_mutex); + auto it = m_peer_map.find(id); + if (it != m_peer_map.end()) { + ret = std::move(it->second); + m_peer_map.erase(it); + } + return ret; +} + +bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) +{ { LOCK(cs_main); CNodeState* state = State(nodeid); @@ -970,7 +1059,7 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { PeerRef peer = GetPeerRef(nodeid); if (peer == nullptr) return false; - stats.m_misbehavior_score = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score); + stats.m_starting_height = peer->m_starting_height; return true; } @@ -1111,7 +1200,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) return nEvicted; } -void PeerManager::Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) +void PeerManagerImpl::Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) { assert(howmuch > 0); @@ -1129,8 +1218,8 @@ void PeerManager::Misbehaving(const NodeId pnode, const int howmuch, const std:: } } -bool PeerManager::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, - bool via_compact_block, const std::string& message) +bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, + bool via_compact_block, const std::string& message) { switch (state.GetResult()) { case BlockValidationResult::BLOCK_RESULT_UNSET: @@ -1152,8 +1241,8 @@ bool PeerManager::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationSt } // Discourage outbound (but not inbound) peers if on an invalid chain. - // Exempt HB compact block peers and manual connections. - if (!via_compact_block && !node_state->m_is_inbound && !node_state->m_is_manual_connection) { + // Exempt HB compact block peers. Manual connections are always protected from discouragement. + if (!via_compact_block && !node_state->m_is_inbound) { Misbehaving(nodeid, 100, message); return true; } @@ -1179,7 +1268,7 @@ bool PeerManager::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationSt return false; } -bool PeerManager::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message) +bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message) { switch (state.GetResult()) { case TxValidationResult::TX_RESULT_UNSET: @@ -1225,14 +1314,23 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT); } -PeerManager::PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman, - CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool) +std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, BanMan* banman, + CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool, + bool ignore_incoming_txs) +{ + return std::make_unique<PeerManagerImpl>(chainparams, connman, banman, scheduler, chainman, pool, ignore_incoming_txs); +} + +PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, BanMan* banman, + CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool, + bool ignore_incoming_txs) : m_chainparams(chainparams), m_connman(connman), m_banman(banman), m_chainman(chainman), m_mempool(pool), - m_stale_tip_check_time(0) + m_stale_tip_check_time(0), + m_ignore_incoming_txs(ignore_incoming_txs) { // Initialize global variables that cannot be constructed at startup. recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); @@ -1262,9 +1360,10 @@ PeerManager::PeerManager(const CChainParams& chainparams, CConnman& connman, Ban /** * Evict orphan txn pool entries (EraseOrphanTx) based on a newly connected - * block. Also save the time of the last tip update. + * block, remember the recently confirmed transactions, and delete tracked + * announcements for them. Also save the time of the last tip update. */ -void PeerManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex) +void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex) { { LOCK(g_cs_orphans); @@ -1306,9 +1405,16 @@ void PeerManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock, co } } } + { + LOCK(cs_main); + for (const auto& ptx : pblock->vtx) { + m_txrequest.ForgetTxHash(ptx->GetHash()); + m_txrequest.ForgetTxHash(ptx->GetWitnessHash()); + } + } } -void PeerManager::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) +void PeerManagerImpl::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) { // To avoid relay problems with transactions that were previously // confirmed, clear our filter of recently confirmed transactions whenever @@ -1333,7 +1439,8 @@ static bool fWitnessesPresentInMostRecentCompactBlock GUARDED_BY(cs_most_recent_ * Maintain state about the best-seen block and fast-announce a compact block * to compatible peers. */ -void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) { +void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) +{ std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs> (*pblock, true); const CNetMsgMaker msgMaker(PROTOCOL_VERSION); @@ -1380,42 +1487,47 @@ void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ * Update our best height and announce any block hashes which weren't previously * in ::ChainActive() to our peers. */ -void PeerManager::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { - const int nNewHeight = pindexNew->nHeight; - m_connman.SetBestHeight(nNewHeight); - +void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) +{ + SetBestHeight(pindexNew->nHeight); SetServiceFlagsIBDCache(!fInitialDownload); - if (!fInitialDownload) { - // Find the hashes of all blocks that weren't previously in the best chain. - std::vector<uint256> vHashes; - const CBlockIndex *pindexToAnnounce = pindexNew; - while (pindexToAnnounce != pindexFork) { - vHashes.push_back(pindexToAnnounce->GetBlockHash()); - pindexToAnnounce = pindexToAnnounce->pprev; - if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) { - // Limit announcements in case of a huge reorganization. - // Rely on the peer's synchronization mechanism in that case. - break; - } + + // Don't relay inventory during initial block download. + if (fInitialDownload) return; + + // Find the hashes of all blocks that weren't previously in the best chain. + std::vector<uint256> vHashes; + const CBlockIndex *pindexToAnnounce = pindexNew; + while (pindexToAnnounce != pindexFork) { + vHashes.push_back(pindexToAnnounce->GetBlockHash()); + pindexToAnnounce = pindexToAnnounce->pprev; + if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) { + // Limit announcements in case of a huge reorganization. + // Rely on the peer's synchronization mechanism in that case. + break; } - // Relay inventory, but don't relay old inventory during initial block download. - m_connman.ForEachNode([nNewHeight, &vHashes](CNode* pnode) { - LOCK(pnode->cs_inventory); - if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) { - for (const uint256& hash : reverse_iterate(vHashes)) { - pnode->vBlockHashesToAnnounce.push_back(hash); - } + } + + { + LOCK(m_peer_mutex); + for (auto& it : m_peer_map) { + Peer& peer = *it.second; + LOCK(peer.m_block_inv_mutex); + for (const uint256& hash : reverse_iterate(vHashes)) { + peer.m_blocks_for_headers_relay.push_back(hash); } - }); - m_connman.WakeMessageHandler(); + } } + + m_connman.WakeMessageHandler(); } /** * Handle invalid block rejection and consequent peer discouragement, maintain which * peers announce compact blocks. */ -void PeerManager::BlockChecked(const CBlock& block, const BlockValidationState& state) { +void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationState& state) +{ LOCK(cs_main); const uint256 hash(block.GetHash()); @@ -1502,8 +1614,25 @@ void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& }); } -static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman) +/** + * Relay (gossip) an address to a few randomly chosen nodes. + * We choose the same nodes within a given 24h window (if the list of connected + * nodes does not change) and we don't relay to nodes that already know an + * address. So within 24h we will likely relay a given address once. This is to + * prevent a peer from unjustly giving their address better propagation by sending + * it to us repeatedly. + * @param[in] originator The peer that sent us the address. We don't want to relay it back. + * @param[in] addr Address to relay. + * @param[in] fReachable Whether the address' network is reachable. We relay unreachable + * addresses less. + * @param[in] connman Connection manager to choose nodes to relay to. + */ +static void RelayAddress(const CNode& originator, + const CAddress& addr, + bool fReachable, + const CConnman& connman) { + if (!fReachable && !addr.IsRelayable()) return; // Relay to a limited number of other nodes // Use deterministic randomness to send to the same nodes for 24 hours @@ -1518,8 +1647,8 @@ static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}}; assert(nRelayNodes <= best.size()); - auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) { - if (pnode->RelayAddrsWithConn()) { + auto sortfunc = [&best, &hasher, nRelayNodes, &originator, &addr](CNode* pnode) { + if (pnode->RelayAddrsWithConn() && pnode != &originator && pnode->IsAddrCompatible(addr)) { uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize(); for (unsigned int i = 0; i < nRelayNodes; i++) { if (hashKey > best[i].first) { @@ -1540,7 +1669,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, const CInv& inv, CConnman& connman) +void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman) { bool send = false; std::shared_ptr<const CBlock> a_recent_block; @@ -1680,16 +1809,18 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c } } - // Trigger the peer node to send a getblocks request for the next batch of inventory - if (inv.hash == pfrom.hashContinue) { - // Send immediately. This must send even if redundant, - // and we want it right after the last block so they don't - // wait for other stuff first. - std::vector<CInv> vInv; - vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash())); - connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv)); - pfrom.hashContinue.SetNull(); + LOCK(peer.m_block_inv_mutex); + // Trigger the peer node to send a getblocks request for the next batch of inventory + if (inv.hash == peer.m_continuation_block) { + // Send immediately. This must send even if redundant, + // and we want it right after the last block so they don't + // wait for other stuff first. + std::vector<CInv> vInv; + vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash())); + connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv)); + peer.m_continuation_block.SetNull(); + } } } } @@ -1722,11 +1853,11 @@ static CTransactionRef FindTxForGetData(const CTxMemPool& mempool, const CNode& return {}; } -void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnman& connman, CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main) +void static ProcessGetData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, CConnman& connman, CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) EXCLUSIVE_LOCKS_REQUIRED(!cs_main, peer.m_getdata_requests_mutex) { AssertLockNotHeld(cs_main); - std::deque<CInv>::iterator it = pfrom.vRecvGetData.begin(); + std::deque<CInv>::iterator it = peer.m_getdata_requests.begin(); std::vector<CInv> vNotFound; const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); @@ -1738,7 +1869,7 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm // Process as many TX items from the front of the getdata queue as // possible, since they're common and it's efficient to batch process // them. - while (it != pfrom.vRecvGetData.end() && it->IsGenTxMsg()) { + while (it != peer.m_getdata_requests.end() && it->IsGenTxMsg()) { if (interruptMsgProc) return; // The send buffer provides backpressure. If there's no space in // the buffer, pause processing until the next call. @@ -1786,16 +1917,16 @@ void static ProcessGetData(CNode& pfrom, const CChainParams& chainparams, CConnm // Only process one BLOCK item per call, since they're uncommon and can be // expensive to process. - if (it != pfrom.vRecvGetData.end() && !pfrom.fPauseSend) { + if (it != peer.m_getdata_requests.end() && !pfrom.fPauseSend) { const CInv &inv = *it++; if (inv.IsGenBlkMsg()) { - ProcessGetBlockData(pfrom, chainparams, inv, connman); + ProcessGetBlockData(pfrom, peer, chainparams, inv, connman); } // else: If the first item on the queue is an unknown type, we erase it // and continue processing the queue on the next call. } - pfrom.vRecvGetData.erase(pfrom.vRecvGetData.begin(), it); + peer.m_getdata_requests.erase(peer.m_getdata_requests.begin(), it); if (!vNotFound.empty()) { // Let the peer know that we didn't find what it asked for, so it doesn't @@ -1824,7 +1955,8 @@ static uint32_t GetFetchFlags(const CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_ma return nFetchFlags; } -void PeerManager::SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req) { +void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req) +{ BlockTransactions resp(req); for (size_t i = 0; i < req.indexes.size(); i++) { if (req.indexes[i] >= block.vtx.size()) { @@ -1839,7 +1971,9 @@ void PeerManager::SendBlockTransactions(CNode& pfrom, const CBlock& block, const m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp)); } -void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHeader>& headers, bool via_compact_block) +void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer, + const std::vector<CBlockHeader>& headers, + bool via_compact_block) { const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); size_t nCount = headers.size(); @@ -1929,7 +2063,8 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe // Headers message had its maximum size; the peer may have more headers. // TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue // from there instead. - LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom.GetId(), pfrom.nStartingHeight); + LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", + pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256())); } @@ -2005,11 +2140,12 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe } } + // If this is an outbound full-relay peer, check to see if we should protect + // it from the bad/lagging chain logic. + // Note that outbound block-relay peers are excluded from this protection, and + // thus always subject to eviction under the bad/lagging chain logic. + // See ChainSyncTimeoutState. if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) { - // If this is an outbound full-relay peer, check to see if we should protect - // it from the bad/lagging chain logic. - // Note that block-relay-only peers are already implicitly protected, so we - // only consider setting m_protect for the full-relay peers. if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId()); nodestate->m_chain_sync.m_protect = true; @@ -2021,13 +2157,20 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe return; } -void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn) +/** + * Reconsider orphan transactions after a parent has been accepted to the mempool. + * + * @param[in/out] orphan_work_set The set of orphan transactions to reconsider. Generally only one + * orphan will be reconsidered on each call of this function. This set + * may be added to if accepting an orphan causes its children to be + * reconsidered. + */ +void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set) { AssertLockHeld(cs_main); AssertLockHeld(g_cs_orphans); - std::set<NodeId> setMisbehaving; - bool done = false; - while (!done && !orphan_work_set.empty()) { + + while (!orphan_work_set.empty()) { const uint256 orphanHash = *orphan_work_set.begin(); orphan_work_set.erase(orphan_work_set.begin()); @@ -2035,18 +2178,13 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list< if (orphan_it == mapOrphanTransactions.end()) continue; const CTransactionRef porphanTx = orphan_it->second.tx; - const CTransaction& orphanTx = *porphanTx; - NodeId fromPeer = orphan_it->second.fromPeer; - // Use a new TxValidationState because orphans come from different peers (and we call - // MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer - // that relayed the previous transaction). - TxValidationState orphan_state; - - if (setMisbehaving.count(fromPeer)) continue; - if (AcceptToMemoryPool(m_mempool, orphan_state, porphanTx, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) { + TxValidationState state; + std::list<CTransactionRef> removed_txn; + + if (AcceptToMemoryPool(m_mempool, state, porphanTx, &removed_txn, false /* bypass_limits */)) { LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString()); RelayTransaction(orphanHash, porphanTx->GetWitnessHash(), m_connman); - for (unsigned int i = 0; i < orphanTx.vout.size(); i++) { + for (unsigned int i = 0; i < porphanTx->vout.size(); i++) { auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(orphanHash, i)); if (it_by_prev != mapOrphanTransactionsByPrev.end()) { for (const auto& elem : it_by_prev->second) { @@ -2055,22 +2193,23 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list< } } EraseOrphanTx(orphanHash); - done = true; - } else if (orphan_state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) { - if (orphan_state.IsInvalid()) { - // Punish peer that gave us an invalid orphan tx - if (MaybePunishNodeForTx(fromPeer, orphan_state)) { - setMisbehaving.insert(fromPeer); - } + for (const CTransactionRef& removedTx : removed_txn) { + AddToCompactExtraTransactions(removedTx); + } + break; + } else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) { + if (state.IsInvalid()) { LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s from peer=%d. %s\n", orphanHash.ToString(), - fromPeer, - orphan_state.ToString()); + orphan_it->second.fromPeer, + state.ToString()); + // Maybe punish peer that gave us an invalid orphan tx + MaybePunishNodeForTx(orphan_it->second.fromPeer, state); } // Has inputs but not accepted to mempool // Probably non-standard or insufficient fee LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString()); - if (orphan_state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) { + if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) { // We can add the wtxid of this transaction to our reject filter. // Do not add txids of witness transactions or witness-stripped // transactions to the filter, as they can have been malleated; @@ -2085,7 +2224,7 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list< // for concerns around weakening security of unupgraded nodes // if we start doing this too early. assert(recentRejects); - recentRejects->insert(orphanTx.GetWitnessHash()); + recentRejects->insert(porphanTx->GetWitnessHash()); // If the transaction failed for TX_INPUTS_NOT_STANDARD, // then we know that the witness was irrelevant to the policy // failure, since this check depends only on the txid @@ -2094,17 +2233,17 @@ void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list< // processing of this transaction in the event that child // transactions are later received (resulting in // parent-fetching by txid via the orphan-handling logic). - if (orphan_state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && orphanTx.GetWitnessHash() != orphanTx.GetHash()) { + if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && porphanTx->GetWitnessHash() != porphanTx->GetHash()) { // We only add the txid if it differs from the wtxid, to // avoid wasting entries in the rolling bloom filter. - recentRejects->insert(orphanTx.GetHash()); + recentRejects->insert(porphanTx->GetHash()); } } EraseOrphanTx(orphanHash); - done = true; + break; } - m_mempool.check(&::ChainstateActive().CoinsTip()); } + m_mempool.check(&::ChainstateActive().CoinsTip()); } /** @@ -2323,23 +2462,18 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar connman.PushMessage(&peer, std::move(msg)); } -void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, - const std::chrono::microseconds time_received, - const std::atomic<bool>& interruptMsgProc) +void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, + const std::chrono::microseconds time_received, + const std::atomic<bool>& interruptMsgProc) { LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId()); - if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0) - { - LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); - return; - } + PeerRef peer = GetPeerRef(pfrom.GetId()); + if (peer == nullptr) return; if (msg_type == NetMsgType::VERSION) { - // Each connection can only send one version message - if (pfrom.nVersion != 0) - { - Misbehaving(pfrom.GetId(), 1, "redundant version message"); + if (pfrom.nVersion != 0) { + LogPrint(BCLog::NET, "redundant version message from peer=%d\n", pfrom.GetId()); return; } @@ -2351,7 +2485,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat ServiceFlags nServices; int nVersion; std::string cleanSubVer; - int nStartingHeight = -1; + int starting_height = -1; bool fRelay = true; vRecv >> nVersion >> nServiceInt >> nTime >> addrMe; @@ -2382,7 +2516,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat cleanSubVer = SanitizeString(strSubVer); } if (!vRecv.empty()) { - vRecv >> nStartingHeight; + vRecv >> starting_height; } if (!vRecv.empty()) vRecv >> fRelay; @@ -2399,20 +2533,31 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat SeenLocal(addrMe); } - // Be shy and don't send version until we hear - if (pfrom.IsInboundConn()) - PushNodeVersion(pfrom, m_connman, GetAdjustedTime()); + // Inbound peers send us their version message when they connect. + // We send our version message in response. + if (pfrom.IsInboundConn()) PushNodeVersion(pfrom, GetAdjustedTime()); // Change version const int greatest_common_version = std::min(nVersion, PROTOCOL_VERSION); pfrom.SetCommonVersion(greatest_common_version); pfrom.nVersion = nVersion; + const CNetMsgMaker msg_maker(greatest_common_version); + if (greatest_common_version >= WTXID_RELAY_VERSION) { - m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::WTXIDRELAY)); + m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::WTXIDRELAY)); + } + + // Signal ADDRv2 support (BIP155). + if (greatest_common_version >= 70016) { + // BIP155 defines addrv2 and sendaddrv2 for all protocol versions, but some + // implementations reject messages they don't know. As a courtesy, don't send + // it to nodes with a version before 70016, as no software is known to support + // BIP155 that doesn't announce at least that protocol version number. + m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::SENDADDRV2)); } - m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::VERACK)); + m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::VERACK)); pfrom.nServices = nServices; pfrom.SetAddrLocal(addrMe); @@ -2420,7 +2565,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat LOCK(pfrom.cs_SubVer); pfrom.cleanSubVer = cleanSubVer; } - pfrom.nStartingHeight = nStartingHeight; + peer->m_starting_height = starting_height; // set nodes not relaying blocks and tx and not serving (parts) of the historical blockchain as "clients" pfrom.fClient = (!(nServices & NODE_NETWORK) && !(nServices & NODE_NETWORK_LIMITED)); @@ -2454,14 +2599,8 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // empty and no one will know who we are, so these mechanisms are // important to help us connect to the network. // - // We also update the addrman to record connection success for - // these peers (which include OUTBOUND_FULL_RELAY and FEELER - // connections) so that addrman will have an up-to-date notion of - // which peers are online and available. - // - // We skip these operations for BLOCK_RELAY peers to avoid - // potentially leaking information about our BLOCK_RELAY - // connections via the addrman or address relay. + // We skip this for block-relay-only peers to avoid potentially leaking + // information about our block-relay-only connections via address relay. if (fListen && !::ChainstateActive().IsInitialBlockDownload()) { CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices()); @@ -2480,9 +2619,23 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // Get recent addresses m_connman.PushMessage(&pfrom, CNetMsgMaker(greatest_common_version).Make(NetMsgType::GETADDR)); pfrom.fGetAddr = true; + } - // Moves address from New to Tried table in Addrman, resolves - // tried-table collisions, etc. + if (!pfrom.IsInboundConn()) { + // For non-inbound connections, we update the addrman to record + // connection success so that addrman will have an up-to-date + // notion of which peers are online and available. + // + // While we strive to not leak information about block-relay-only + // connections via the addrman, not moving an address to the tried + // table is also potentially detrimental because new-table entries + // are subject to eviction in the event of addrman collisions. We + // mitigate the information-leak by never calling + // CAddrMan::Connected() on block-relay-only peers; see + // FinalizeNode(). + // + // This moves an address from New to Tried table in Addrman, + // resolves tried-table collisions, etc. m_connman.MarkAddressGood(pfrom.addr); } @@ -2490,9 +2643,9 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat if (fLogIPs) remoteAddr = ", peeraddr=" + pfrom.addr.ToString(); - LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", + LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s\n", cleanSubVer, pfrom.nVersion, - pfrom.nStartingHeight, addrMe.ToString(), pfrom.GetId(), + peer->m_starting_height, addrMe.ToString(), fRelay, pfrom.GetId(), remoteAddr); int64_t nTimeOffset = nTime - GetTime(); @@ -2507,6 +2660,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // Feeler connections exist only to verify if address is online. if (pfrom.IsFeelerConn()) { + LogPrint(BCLog::NET, "feeler connection completed peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; } return; @@ -2514,23 +2668,24 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat if (pfrom.nVersion == 0) { // Must have a version message before anything else - Misbehaving(pfrom.GetId(), 1, "non-version message before version handshake"); + LogPrint(BCLog::NET, "non-version message before version handshake. Message \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); return; } // At this point, the outgoing message serialization version can't change. const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); - if (msg_type == NetMsgType::VERACK) - { + if (msg_type == NetMsgType::VERACK) { + if (pfrom.fSuccessfullyConnected) { + LogPrint(BCLog::NET, "ignoring redundant verack message from peer=%d\n", pfrom.GetId()); + return; + } + if (!pfrom.IsInboundConn()) { - // Mark this node as currently connected, so we update its timestamp later. - LOCK(cs_main); - State(pfrom.GetId())->fCurrentlyConnected = true; LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n", - pfrom.nVersion.load(), pfrom.nStartingHeight, + pfrom.nVersion.load(), peer->m_starting_height, pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToString()) : ""), - pfrom.m_tx_relay == nullptr ? "block-relay" : "full-relay"); + pfrom.ConnectionTypeAsString()); } if (pfrom.GetCommonVersion() >= SENDHEADERS_VERSION) { @@ -2557,12 +2712,46 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat return; } - // Feature negotiation of wtxidrelay should happen between VERSION and - // VERACK, to avoid relay problems from switching after a connection is up + if (msg_type == NetMsgType::SENDHEADERS) { + LOCK(cs_main); + State(pfrom.GetId())->fPreferHeaders = true; + return; + } + + if (msg_type == NetMsgType::SENDCMPCT) { + bool fAnnounceUsingCMPCTBLOCK = false; + uint64_t nCMPCTBLOCKVersion = 0; + vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; + if (nCMPCTBLOCKVersion == 1 || ((pfrom.GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) { + LOCK(cs_main); + // fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness) + if (!State(pfrom.GetId())->fProvidesHeaderAndIDs) { + State(pfrom.GetId())->fProvidesHeaderAndIDs = true; + State(pfrom.GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2; + } + if (State(pfrom.GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) { // ignore later version announces + State(pfrom.GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; + // save whether peer selects us as BIP152 high-bandwidth peer + // (receiving sendcmpct(1) signals high-bandwidth, sendcmpct(0) low-bandwidth) + pfrom.m_bip152_highbandwidth_from = fAnnounceUsingCMPCTBLOCK; + } + if (!State(pfrom.GetId())->fSupportsDesiredCmpctVersion) { + if (pfrom.GetLocalServices() & NODE_WITNESS) + State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2); + else + State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1); + } + } + return; + } + + // Feature negotiation of wtxidrelay must happen between VERSION and VERACK + // to avoid relay problems from switching after a connection is up. if (msg_type == NetMsgType::WTXIDRELAY) { if (pfrom.fSuccessfullyConnected) { // Disconnect peers that send wtxidrelay message after VERACK; this // must be negotiated between VERSION and VERACK. + LogPrint(BCLog::NET, "wtxidrelay received after verack from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -2571,27 +2760,52 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat if (!State(pfrom.GetId())->m_wtxid_relay) { State(pfrom.GetId())->m_wtxid_relay = true; g_wtxid_relay_peers++; + } else { + LogPrint(BCLog::NET, "ignoring duplicate wtxidrelay from peer=%d\n", pfrom.GetId()); } + } else { + LogPrint(BCLog::NET, "ignoring wtxidrelay due to old common version=%d from peer=%d\n", pfrom.GetCommonVersion(), pfrom.GetId()); } return; } + if (msg_type == NetMsgType::SENDADDRV2) { + if (pfrom.fSuccessfullyConnected) { + // Disconnect peers that send SENDADDRV2 message after VERACK; this + // must be negotiated between VERSION and VERACK. + LogPrint(BCLog::NET, "sendaddrv2 received after verack from peer=%d; disconnecting\n", pfrom.GetId()); + pfrom.fDisconnect = true; + return; + } + pfrom.m_wants_addrv2 = true; + return; + } + if (!pfrom.fSuccessfullyConnected) { - // Must have a verack message before anything else - Misbehaving(pfrom.GetId(), 1, "non-verack message before version handshake"); + LogPrint(BCLog::NET, "Unsupported message \"%s\" prior to verack from peer=%d\n", SanitizeString(msg_type), pfrom.GetId()); return; } - if (msg_type == NetMsgType::ADDR) { + if (msg_type == NetMsgType::ADDR || msg_type == NetMsgType::ADDRV2) { + int stream_version = vRecv.GetVersion(); + if (msg_type == NetMsgType::ADDRV2) { + // Add ADDRV2_FORMAT to the version so that the CNetAddr and CAddress + // unserialize methods know that an address in v2 format is coming. + stream_version |= ADDRV2_FORMAT; + } + + OverrideStream<CDataStream> s(&vRecv, vRecv.GetType(), stream_version); std::vector<CAddress> vAddr; - vRecv >> vAddr; + + s >> vAddr; if (!pfrom.RelayAddrsWithConn()) { + LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId()); return; } if (vAddr.size() > MAX_ADDR_TO_SEND) { - Misbehaving(pfrom.GetId(), 20, strprintf("addr message size = %u", vAddr.size())); + Misbehaving(pfrom.GetId(), 20, strprintf("%s message size = %u", msg_type, vAddr.size())); return; } @@ -2621,7 +2835,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat if (addr.nTime > nSince && !pfrom.fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) { // Relay to a limited number of other nodes - RelayAddress(addr, fReachable, m_connman); + RelayAddress(pfrom, addr, fReachable, m_connman); } // Do not store addresses outside our network if (fReachable) @@ -2630,36 +2844,9 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat m_connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60); if (vAddr.size() < 1000) pfrom.fGetAddr = false; - if (pfrom.IsAddrFetchConn()) + if (pfrom.IsAddrFetchConn()) { + LogPrint(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; - return; - } - - if (msg_type == NetMsgType::SENDHEADERS) { - LOCK(cs_main); - State(pfrom.GetId())->fPreferHeaders = true; - return; - } - - if (msg_type == NetMsgType::SENDCMPCT) { - bool fAnnounceUsingCMPCTBLOCK = false; - uint64_t nCMPCTBLOCKVersion = 0; - vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; - if (nCMPCTBLOCKVersion == 1 || ((pfrom.GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) { - LOCK(cs_main); - // fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness) - if (!State(pfrom.GetId())->fProvidesHeaderAndIDs) { - State(pfrom.GetId())->fProvidesHeaderAndIDs = true; - State(pfrom.GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2; - } - if (State(pfrom.GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces - State(pfrom.GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; - if (!State(pfrom.GetId())->fSupportsDesiredCmpctVersion) { - if (pfrom.GetLocalServices() & NODE_WITNESS) - State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2); - else - State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1); - } } return; } @@ -2675,7 +2862,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // We won't accept tx inv's if we're in blocks-only mode, or this is a // block-relay-only peer - bool fBlocksOnly = !g_relay_txes || (pfrom.m_tx_relay == nullptr); + bool fBlocksOnly = m_ignore_incoming_txs || (pfrom.m_tx_relay == nullptr); // Allow peers with relay permission to send data other than blocks in blocks only mode if (pfrom.HasPermission(PF_RELAY)) { @@ -2723,7 +2910,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat pfrom.fDisconnect = true; return; } else if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) { - RequestTx(State(pfrom.GetId()), gtxid, current_time); + AddTxAnnouncement(pfrom, gtxid, current_time); } } else { LogPrint(BCLog::NET, "Unknown inv type \"%s\" received from peer=%d\n", inv.ToString(), pfrom.GetId()); @@ -2753,8 +2940,12 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat LogPrint(BCLog::NET, "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom.GetId()); } - pfrom.vRecvGetData.insert(pfrom.vRecvGetData.end(), vInv.begin(), vInv.end()); - ProcessGetData(pfrom, m_chainparams, m_connman, m_mempool, interruptMsgProc); + { + LOCK(peer->m_getdata_requests_mutex); + peer->m_getdata_requests.insert(peer->m_getdata_requests.end(), vInv.begin(), vInv.end()); + ProcessGetData(pfrom, *peer, m_chainparams, m_connman, m_mempool, interruptMsgProc); + } + return; } @@ -2813,13 +3004,12 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); break; } - WITH_LOCK(pfrom.cs_inventory, pfrom.vInventoryBlockToSend.push_back(pindex->GetBlockHash())); - if (--nLimit <= 0) - { + WITH_LOCK(peer->m_block_inv_mutex, peer->m_blocks_for_inv_relay.push_back(pindex->GetBlockHash())); + if (--nLimit <= 0) { // When this block is requested, we'll send an inv that'll // trigger the peer to getblocks the next batch of inventory. LogPrint(BCLog::NET, " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - pfrom.hashContinue = pindex->GetBlockHash(); + WITH_LOCK(peer->m_block_inv_mutex, {peer->m_continuation_block = pindex->GetBlockHash();}); break; } } @@ -2842,36 +3032,38 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat return; } - LOCK(cs_main); + { + LOCK(cs_main); - const CBlockIndex* pindex = LookupBlockIndex(req.blockhash); - if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) { - LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId()); - return; - } + const CBlockIndex* pindex = LookupBlockIndex(req.blockhash); + if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) { + LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId()); + return; + } - if (pindex->nHeight < ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) { - // If an older block is requested (should never happen in practice, - // but can happen in tests) send a block response instead of a - // blocktxn response. Sending a full block response instead of a - // small blocktxn response is preferable in the case where a peer - // might maliciously send lots of getblocktxn requests to trigger - // expensive disk reads, because it will require the peer to - // actually receive all the data read from disk over the network. - LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom.GetId(), MAX_BLOCKTXN_DEPTH); - CInv inv; - inv.type = State(pfrom.GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK; - inv.hash = req.blockhash; - pfrom.vRecvGetData.push_back(inv); - // The message processing loop will go around again (without pausing) and we'll respond then (without cs_main) - return; - } + if (pindex->nHeight >= ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) { + CBlock block; + bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus()); + assert(ret); - CBlock block; - bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus()); - assert(ret); + SendBlockTransactions(pfrom, block, req); + return; + } + } - SendBlockTransactions(pfrom, block, req); + // If an older block is requested (should never happen in practice, + // but can happen in tests) send a block response instead of a + // blocktxn response. Sending a full block response instead of a + // small blocktxn response is preferable in the case where a peer + // might maliciously send lots of getblocktxn requests to trigger + // expensive disk reads, because it will require the peer to + // actually receive all the data read from disk over the network. + LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom.GetId(), MAX_BLOCKTXN_DEPTH); + CInv inv; + WITH_LOCK(cs_main, inv.type = State(pfrom.GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK); + inv.hash = req.blockhash; + WITH_LOCK(peer->m_getdata_requests_mutex, peer->m_getdata_requests.push_back(inv)); + // The message processing loop will go around again (without pausing) and we'll respond then return; } @@ -2946,7 +3138,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // Stop processing the transaction early if // 1) We are in blocks only mode and peer has no relay permission // 2) This peer is a block-relay-only peer - if ((!g_relay_txes && !pfrom.HasPermission(PF_RELAY)) || (pfrom.m_tx_relay == nullptr)) + if ((m_ignore_incoming_txs && !pfrom.HasPermission(PF_RELAY)) || (pfrom.m_tx_relay == nullptr)) { LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom.GetId()); pfrom.fDisconnect = true; @@ -2975,15 +3167,8 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat pfrom.AddKnownTx(txid); } - TxValidationState state; - - for (const GenTxid& gtxid : {GenTxid(false, txid), GenTxid(true, wtxid)}) { - nodestate->m_tx_download.m_tx_announced.erase(gtxid.GetHash()); - nodestate->m_tx_download.m_tx_in_flight.erase(gtxid.GetHash()); - EraseTxRequest(gtxid); - } - - std::list<CTransactionRef> lRemovedTxn; + m_txrequest.ReceivedResponse(pfrom.GetId(), txid); + if (tx.HasWitness()) m_txrequest.ReceivedResponse(pfrom.GetId(), wtxid); // We do the AlreadyHaveTx() check using wtxid, rather than txid - in the // absence of witness malleation, this is strictly better, because the @@ -2997,15 +3182,36 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // already; and an adversary can already relay us old transactions // (older than our recency filter) if trying to DoS us, without any need // for witness malleation. - if (!AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid), m_mempool) && - AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) { + if (AlreadyHaveTx(GenTxid(/* is_wtxid=*/true, wtxid), m_mempool)) { + if (pfrom.HasPermission(PF_FORCERELAY)) { + // Always relay transactions received from peers with forcerelay + // permission, even if they were already in the mempool, allowing + // the node to function as a gateway for nodes hidden behind it. + if (!m_mempool.exists(tx.GetHash())) { + LogPrintf("Not relaying non-mempool transaction %s from forcerelay peer=%d\n", tx.GetHash().ToString(), pfrom.GetId()); + } else { + LogPrintf("Force relaying tx %s from peer=%d\n", tx.GetHash().ToString(), pfrom.GetId()); + RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman); + } + } + return; + } + + TxValidationState state; + std::list<CTransactionRef> lRemovedTxn; + + if (AcceptToMemoryPool(m_mempool, state, ptx, &lRemovedTxn, false /* bypass_limits */)) { m_mempool.check(&::ChainstateActive().CoinsTip()); + // As this version of the transaction was acceptable, we can forget about any + // requests for it. + m_txrequest.ForgetTxHash(tx.GetHash()); + m_txrequest.ForgetTxHash(tx.GetWitnessHash()); RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman); for (unsigned int i = 0; i < tx.vout.size(); i++) { auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(txid, i)); if (it_by_prev != mapOrphanTransactionsByPrev.end()) { for (const auto& elem : it_by_prev->second) { - pfrom.orphan_work_set.insert(elem->first); + peer->m_orphan_work_set.insert(elem->first); } } } @@ -3017,8 +3223,12 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat tx.GetHash().ToString(), m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000); + for (const CTransactionRef& removedTx : lRemovedTxn) { + AddToCompactExtraTransactions(removedTx); + } + // Recursively process any orphan transactions that depended on this one - ProcessOrphanTx(pfrom.orphan_work_set, lRemovedTxn); + ProcessOrphanTx(peer->m_orphan_work_set); } else if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { @@ -3051,10 +3261,14 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // protocol for getting all unconfirmed parents. const GenTxid gtxid{/* is_wtxid=*/false, parent_txid}; pfrom.AddKnownTx(parent_txid); - if (!AlreadyHaveTx(gtxid, m_mempool)) RequestTx(State(pfrom.GetId()), gtxid, current_time); + if (!AlreadyHaveTx(gtxid, m_mempool)) AddTxAnnouncement(pfrom, gtxid, current_time); } AddOrphanTx(ptx, pfrom.GetId()); + // Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore. + m_txrequest.ForgetTxHash(tx.GetHash()); + m_txrequest.ForgetTxHash(tx.GetWitnessHash()); + // DoS prevention: do not allow mapOrphanTransactions to grow unbounded (see CVE-2012-3789) unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, gArgs.GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); @@ -3071,6 +3285,8 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // from any of our non-wtxidrelay peers. recentRejects->insert(tx.GetHash()); recentRejects->insert(tx.GetWitnessHash()); + m_txrequest.ForgetTxHash(tx.GetHash()); + m_txrequest.ForgetTxHash(tx.GetWitnessHash()); } } else { if (state.GetResult() != TxValidationResult::TX_WITNESS_STRIPPED) { @@ -3089,6 +3305,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // if we start doing this too early. assert(recentRejects); recentRejects->insert(tx.GetWitnessHash()); + m_txrequest.ForgetTxHash(tx.GetWitnessHash()); // If the transaction failed for TX_INPUTS_NOT_STANDARD, // then we know that the witness was irrelevant to the policy // failure, since this check depends only on the txid @@ -3099,29 +3316,14 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // parent-fetching by txid via the orphan-handling logic). if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && tx.GetWitnessHash() != tx.GetHash()) { recentRejects->insert(tx.GetHash()); + m_txrequest.ForgetTxHash(tx.GetHash()); } if (RecursiveDynamicUsage(*ptx) < 100000) { AddToCompactExtraTransactions(ptx); } } - - if (pfrom.HasPermission(PF_FORCERELAY)) { - // Always relay transactions received from peers with forcerelay permission, even - // if they were already in the mempool, - // allowing the node to function as a gateway for - // nodes hidden behind it. - if (!m_mempool.exists(tx.GetHash())) { - LogPrintf("Not relaying non-mempool transaction %s from forcerelay peer=%d\n", tx.GetHash().ToString(), pfrom.GetId()); - } else { - LogPrintf("Force relaying tx %s from peer=%d\n", tx.GetHash().ToString(), pfrom.GetId()); - RelayTransaction(tx.GetHash(), tx.GetWitnessHash(), m_connman); - } - } } - for (const CTransactionRef& removedTx : lRemovedTxn) - AddToCompactExtraTransactions(removedTx); - // If a tx has been detected by recentRejects, we will have reached // this point and the tx will have been ignored. Because we haven't run // the tx through AcceptToMemoryPool, we won't have computed a DoS @@ -3331,7 +3533,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // the peer if the header turns out to be for an invalid block. // Note that if a peer tries to build on an invalid chain, that // will be detected and the peer will be disconnected/discouraged. - return ProcessHeadersMessage(pfrom, {cmpctblock.header}, /*via_compact_block=*/true); + return ProcessHeadersMessage(pfrom, *peer, {cmpctblock.header}, /*via_compact_block=*/true); } if (fBlockReconstructed) { @@ -3474,7 +3676,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat ReadCompactSize(vRecv); // ignore tx count; assume it is 0. } - return ProcessHeadersMessage(pfrom, headers, /*via_compact_block=*/false); + return ProcessHeadersMessage(pfrom, *peer, headers, /*via_compact_block=*/false); } if (msg_type == NetMsgType::BLOCK) @@ -3610,7 +3812,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat // Matching pong received, this ping is no longer outstanding bPingFinished = true; const auto ping_time = ping_end - pfrom.m_ping_start.load(); - if (ping_time.count() > 0) { + if (ping_time.count() >= 0) { // Successful ping time measurement, replace previous pfrom.nPingUsecTime = count_microseconds(ping_time); pfrom.nMinPingUsecTime = std::min(pfrom.nMinPingUsecTime.load(), count_microseconds(ping_time)); @@ -3652,6 +3854,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat if (msg_type == NetMsgType::FILTERLOAD) { if (!(pfrom.GetLocalServices() & NODE_BLOOM)) { + LogPrint(BCLog::NET, "filterload received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -3674,6 +3877,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat if (msg_type == NetMsgType::FILTERADD) { if (!(pfrom.GetLocalServices() & NODE_BLOOM)) { + LogPrint(BCLog::NET, "filteradd received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -3701,6 +3905,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat if (msg_type == NetMsgType::FILTERCLEAR) { if (!(pfrom.GetLocalServices() & NODE_BLOOM)) { + LogPrint(BCLog::NET, "filterclear received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId()); pfrom.fDisconnect = true; return; } @@ -3718,7 +3923,6 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat vRecv >> newFeeFilter; if (MoneyRange(newFeeFilter)) { if (pfrom.m_tx_relay != nullptr) { - LOCK(pfrom.m_tx_relay->cs_feeFilter); pfrom.m_tx_relay->minFeeFilter = newFeeFilter; } LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId()); @@ -3742,24 +3946,15 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat } if (msg_type == NetMsgType::NOTFOUND) { - // Remove the NOTFOUND transactions from the peer - LOCK(cs_main); - CNodeState *state = State(pfrom.GetId()); std::vector<CInv> vInv; vRecv >> vInv; - if (vInv.size() <= MAX_PEER_TX_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (vInv.size() <= MAX_PEER_TX_ANNOUNCEMENTS + MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + LOCK(::cs_main); for (CInv &inv : vInv) { if (inv.IsGenTxMsg()) { - // If we receive a NOTFOUND message for a txid we requested, erase - // it from our data structures for this peer. - auto in_flight_it = state->m_tx_download.m_tx_in_flight.find(inv.hash); - if (in_flight_it == state->m_tx_download.m_tx_in_flight.end()) { - // Skip any further work if this is a spurious NOTFOUND - // message. - continue; - } - state->m_tx_download.m_tx_in_flight.erase(in_flight_it); - state->m_tx_download.m_tx_announced.erase(inv.hash); + // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as + // completed in TxRequestTracker. + m_txrequest.ReceivedResponse(pfrom.GetId(), inv.hash); } } } @@ -3771,7 +3966,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat return; } -bool PeerManager::MaybeDiscourageAndDisconnect(CNode& pnode) +bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode) { const NodeId peer_id{pnode.GetId()}; PeerRef peer = GetPeerRef(peer_id); @@ -3807,25 +4002,30 @@ bool PeerManager::MaybeDiscourageAndDisconnect(CNode& pnode) } // Normal case: Disconnect the peer and discourage all nodes sharing the address - LogPrintf("Disconnecting and discouraging peer %d!\n", peer_id); + LogPrint(BCLog::NET, "Disconnecting and discouraging peer %d!\n", peer_id); if (m_banman) m_banman->Discourage(pnode.addr); m_connman.DisconnectNode(pnode.addr); return true; } -bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc) +bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc) { bool fMoreWork = false; - if (!pfrom->vRecvGetData.empty()) - ProcessGetData(*pfrom, m_chainparams, m_connman, m_mempool, interruptMsgProc); + PeerRef peer = GetPeerRef(pfrom->GetId()); + if (peer == nullptr) return false; - if (!pfrom->orphan_work_set.empty()) { - std::list<CTransactionRef> removed_txn; + { + LOCK(peer->m_getdata_requests_mutex); + if (!peer->m_getdata_requests.empty()) { + ProcessGetData(*pfrom, *peer, m_chainparams, m_connman, m_mempool, interruptMsgProc); + } + } + + { LOCK2(cs_main, g_cs_orphans); - ProcessOrphanTx(pfrom->orphan_work_set, removed_txn); - for (const CTransactionRef& removedTx : removed_txn) { - AddToCompactExtraTransactions(removedTx); + if (!peer->m_orphan_work_set.empty()) { + ProcessOrphanTx(peer->m_orphan_work_set); } } @@ -3833,9 +4033,16 @@ bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgP return false; // this maintains the order of responses - // and prevents vRecvGetData to grow unbounded - if (!pfrom->vRecvGetData.empty()) return true; - if (!pfrom->orphan_work_set.empty()) return true; + // and prevents m_getdata_requests to grow unbounded + { + LOCK(peer->m_getdata_requests_mutex); + if (!peer->m_getdata_requests.empty()) return true; + } + + { + LOCK(g_cs_orphans); + if (!peer->m_orphan_work_set.empty()) return true; + } // Don't bother if send buffer is too full to respond anyway if (pfrom->fPauseSend) @@ -3862,10 +4069,11 @@ bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgP try { ProcessMessage(*pfrom, msg_type, msg.m_recv, msg.m_time, interruptMsgProc); - if (interruptMsgProc) - return false; - if (!pfrom->vRecvGetData.empty()) - fMoreWork = true; + if (interruptMsgProc) return false; + { + LOCK(peer->m_getdata_requests_mutex); + if (!peer->m_getdata_requests.empty()) fMoreWork = true; + } } catch (const std::exception& e) { LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(msg_type), nMessageSize, e.what(), typeid(e).name()); } catch (...) { @@ -3875,7 +4083,7 @@ bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgP return fMoreWork; } -void PeerManager::ConsiderEviction(CNode& pto, int64_t time_in_seconds) +void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds) { AssertLockHeld(cs_main); @@ -3928,13 +4136,56 @@ void PeerManager::ConsiderEviction(CNode& pto, int64_t time_in_seconds) } } -void PeerManager::EvictExtraOutboundPeers(int64_t time_in_seconds) +void PeerManagerImpl::EvictExtraOutboundPeers(int64_t time_in_seconds) { - // Check whether we have too many outbound peers - int extra_peers = m_connman.GetExtraOutboundCount(); - if (extra_peers > 0) { - // If we have more outbound peers than we target, disconnect one. - // Pick the outbound peer that least recently announced + // If we have any extra block-relay-only peers, disconnect the youngest unless + // it's given us a block -- in which case, compare with the second-youngest, and + // out of those two, disconnect the peer who least recently gave us a block. + // The youngest block-relay-only peer would be the extra peer we connected + // to temporarily in order to sync our tip; see net.cpp. + // Note that we use higher nodeid as a measure for most recent connection. + if (m_connman.GetExtraBlockRelayCount() > 0) { + std::pair<NodeId, int64_t> youngest_peer{-1, 0}, next_youngest_peer{-1, 0}; + + m_connman.ForEachNode([&](CNode* pnode) { + if (!pnode->IsBlockOnlyConn() || pnode->fDisconnect) return; + if (pnode->GetId() > youngest_peer.first) { + next_youngest_peer = youngest_peer; + youngest_peer.first = pnode->GetId(); + youngest_peer.second = pnode->nLastBlockTime; + } + }); + NodeId to_disconnect = youngest_peer.first; + if (youngest_peer.second > next_youngest_peer.second) { + // Our newest block-relay-only peer gave us a block more recently; + // disconnect our second youngest. + to_disconnect = next_youngest_peer.first; + } + m_connman.ForNode(to_disconnect, [&](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); + // Make sure we're not getting a block right now, and that + // we've been connected long enough for this eviction to happen + // at all. + // Note that we only request blocks from a peer if we learn of a + // valid headers chain with at least as much work as our tip. + CNodeState *node_state = State(pnode->GetId()); + if (node_state == nullptr || + (time_in_seconds - pnode->nTimeConnected >= MINIMUM_CONNECT_TIME && node_state->nBlocksInFlight == 0)) { + pnode->fDisconnect = true; + LogPrint(BCLog::NET, "disconnecting extra block-relay-only peer=%d (last block received at time %d)\n", pnode->GetId(), pnode->nLastBlockTime); + return true; + } else { + LogPrint(BCLog::NET, "keeping block-relay-only peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", + pnode->GetId(), pnode->nTimeConnected, node_state->nBlocksInFlight); + } + return false; + }); + } + + // Check whether we have too many outbound-full-relay peers + if (m_connman.GetExtraFullOutboundCount() > 0) { + // If we have more outbound-full-relay peers than we target, disconnect one. + // Pick the outbound-full-relay peer that least recently announced // us a new block, with ties broken by choosing the more recent // connection (higher node id) NodeId worst_peer = -1; @@ -3943,14 +4194,13 @@ void PeerManager::EvictExtraOutboundPeers(int64_t time_in_seconds) m_connman.ForEachNode([&](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { AssertLockHeld(::cs_main); - // Ignore non-outbound peers, or nodes marked for disconnect already - if (!pnode->IsOutboundOrBlockRelayConn() || pnode->fDisconnect) return; + // Only consider outbound-full-relay peers that are not already + // marked for disconnection + if (!pnode->IsFullOutboundConn() || pnode->fDisconnect) return; CNodeState *state = State(pnode->GetId()); if (state == nullptr) return; // shouldn't be possible, but just in case // Don't evict our protected peers if (state->m_chain_sync.m_protect) return; - // Don't evict our block-relay-only peers. - if (pnode->m_tx_relay == nullptr) return; if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) { worst_peer = pnode->GetId(); oldest_block_announcement = state->m_last_block_announcement; @@ -3987,7 +4237,7 @@ void PeerManager::EvictExtraOutboundPeers(int64_t time_in_seconds) } } -void PeerManager::CheckForStaleTipAndEvictPeers() +void PeerManagerImpl::CheckForStaleTipAndEvictPeers() { LOCK(cs_main); @@ -4006,6 +4256,11 @@ void PeerManager::CheckForStaleTipAndEvictPeers() } m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL; } + + if (!m_initial_sync_finished && CanDirectFetch(m_chainparams.GetConsensus())) { + m_connman.StartExtraBlockRelayPeers(); + m_initial_sync_finished = true; + } } namespace { @@ -4029,8 +4284,9 @@ public: }; } -bool PeerManager::SendMessages(CNode* pto) +bool PeerManagerImpl::SendMessages(CNode* pto) { + PeerRef peer = GetPeerRef(pto->GetId()); const Consensus::Params& consensusParams = m_chainparams.GetConsensus(); // We must call MaybeDiscourageAndDisconnect first, to ensure that we'll @@ -4079,10 +4335,18 @@ bool PeerManager::SendMessages(CNode* pto) CNodeState &state = *State(pto->GetId()); // Address refresh broadcast - int64_t nNow = GetTimeMicros(); auto current_time = GetTime<std::chrono::microseconds>(); if (pto->RelayAddrsWithConn() && !::ChainstateActive().IsInitialBlockDownload() && pto->m_next_local_addr_send < current_time) { + // If we've sent before, clear the bloom filter for the peer, so that our + // self-announcement will actually go out. + // This might be unnecessary if the bloom filter has already rolled + // over since our last self-announcement, but there is only a small + // bandwidth cost that we can incur by doing this (which happens + // once a day on average). + if (pto->m_next_local_addr_send != 0us) { + pto->m_addr_known->reset(); + } AdvertiseLocal(pto); pto->m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); } @@ -4095,6 +4359,17 @@ bool PeerManager::SendMessages(CNode* pto) std::vector<CAddress> vAddr; vAddr.reserve(pto->vAddrToSend.size()); assert(pto->m_addr_known); + + const char* msg_type; + int make_flags; + if (pto->m_wants_addrv2) { + msg_type = NetMsgType::ADDRV2; + make_flags = ADDRV2_FORMAT; + } else { + msg_type = NetMsgType::ADDR; + make_flags = 0; + } + for (const CAddress& addr : pto->vAddrToSend) { if (!pto->m_addr_known->contains(addr.GetKey())) @@ -4104,14 +4379,14 @@ bool PeerManager::SendMessages(CNode* pto) // receiver rejects addr messages larger than MAX_ADDR_TO_SEND if (vAddr.size() >= MAX_ADDR_TO_SEND) { - m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); + m_connman.PushMessage(pto, msgMaker.Make(make_flags, msg_type, vAddr)); vAddr.clear(); } } } pto->vAddrToSend.clear(); if (!vAddr.empty()) - m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::ADDR, vAddr)); + m_connman.PushMessage(pto, msgMaker.Make(make_flags, msg_type, vAddr)); // we only send the big addr message once if (pto->vAddrToSend.capacity() > 40) pto->vAddrToSend.shrink_to_fit(); @@ -4125,7 +4400,7 @@ bool PeerManager::SendMessages(CNode* pto) // Only actively request headers from a single peer, unless we're close to today. if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { state.fSyncStarted = true; - state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(consensusParams.nPowTargetSpacing); + state.nHeadersSyncTimeout = count_microseconds(current_time) + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(consensusParams.nPowTargetSpacing); nSyncStarted++; const CBlockIndex *pindexStart = pindexBestHeader; /* If possible, start at the block preceding the currently @@ -4137,7 +4412,7 @@ bool PeerManager::SendMessages(CNode* pto) got back an empty response. */ if (pindexStart->pprev) pindexStart = pindexStart->pprev; - LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight); + LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height); m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256())); } } @@ -4153,11 +4428,11 @@ bool PeerManager::SendMessages(CNode* pto) // If no header would connect, or if we have too many // blocks, or if the peer doesn't want headers, just // add all to the inv queue. - LOCK(pto->cs_inventory); + LOCK(peer->m_block_inv_mutex); std::vector<CBlock> vHeaders; bool fRevertToInv = ((!state.fPreferHeaders && - (!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) || - pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE); + (!state.fPreferHeaderAndIDs || peer->m_blocks_for_headers_relay.size() > 1)) || + peer->m_blocks_for_headers_relay.size() > MAX_BLOCKS_TO_ANNOUNCE); const CBlockIndex *pBestIndex = nullptr; // last header queued for delivery ProcessBlockAvailability(pto->GetId()); // ensure pindexBestKnownBlock is up-to-date @@ -4166,7 +4441,7 @@ bool PeerManager::SendMessages(CNode* pto) // Try to find first header that our peer doesn't have, and // then send all headers past that one. If we come across any // headers that aren't on ::ChainActive(), give up. - for (const uint256 &hash : pto->vBlockHashesToAnnounce) { + for (const uint256& hash : peer->m_blocks_for_headers_relay) { const CBlockIndex* pindex = LookupBlockIndex(hash); assert(pindex); if (::ChainActive()[pindex->nHeight] != pindex) { @@ -4183,7 +4458,7 @@ bool PeerManager::SendMessages(CNode* pto) // which should be caught by the prior check), but one // way this could happen is by using invalidateblock / // reconsiderblock repeatedly on the tip, causing it to - // be added multiple times to vBlockHashesToAnnounce. + // be added multiple times to m_blocks_for_headers_relay. // Robustly deal with this rare situation by reverting // to an inv. fRevertToInv = true; @@ -4255,10 +4530,10 @@ bool PeerManager::SendMessages(CNode* pto) } if (fRevertToInv) { // If falling back to using an inv, just try to inv the tip. - // The last entry in vBlockHashesToAnnounce was our tip at some point + // The last entry in m_blocks_for_headers_relay was our tip at some point // in the past. - if (!pto->vBlockHashesToAnnounce.empty()) { - const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); + if (!peer->m_blocks_for_headers_relay.empty()) { + const uint256& hashToAnnounce = peer->m_blocks_for_headers_relay.back(); const CBlockIndex* pindex = LookupBlockIndex(hashToAnnounce); assert(pindex); @@ -4272,13 +4547,13 @@ bool PeerManager::SendMessages(CNode* pto) // If the peer's chain has this block, don't inv it back. if (!PeerHasHeader(&state, pindex)) { - pto->vInventoryBlockToSend.push_back(hashToAnnounce); + peer->m_blocks_for_inv_relay.push_back(hashToAnnounce); LogPrint(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", __func__, pto->GetId(), hashToAnnounce.ToString()); } } } - pto->vBlockHashesToAnnounce.clear(); + peer->m_blocks_for_headers_relay.clear(); } // @@ -4286,18 +4561,18 @@ bool PeerManager::SendMessages(CNode* pto) // std::vector<CInv> vInv; { - LOCK(pto->cs_inventory); - vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX)); + LOCK(peer->m_block_inv_mutex); + vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(), INVENTORY_BROADCAST_MAX)); // Add blocks - for (const uint256& hash : pto->vInventoryBlockToSend) { + for (const uint256& hash : peer->m_blocks_for_inv_relay) { vInv.push_back(CInv(MSG_BLOCK, hash)); if (vInv.size() == MAX_INV_SZ) { m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); vInv.clear(); } } - pto->vInventoryBlockToSend.clear(); + peer->m_blocks_for_inv_relay.clear(); if (pto->m_tx_relay != nullptr) { LOCK(pto->m_tx_relay->cs_tx_inventory); @@ -4306,7 +4581,7 @@ bool PeerManager::SendMessages(CNode* pto) if (pto->m_tx_relay->nNextInvSend < current_time) { fSendTrickle = true; if (pto->IsInboundConn()) { - pto->m_tx_relay->nNextInvSend = std::chrono::microseconds{m_connman.PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL)}; + pto->m_tx_relay->nNextInvSend = std::chrono::microseconds{m_connman.PoissonNextSendInbound(count_microseconds(current_time), INVENTORY_BROADCAST_INTERVAL)}; } else { // Use half the delay for outbound peers, as there is less privacy concern for them. pto->m_tx_relay->nNextInvSend = PoissonNextSend(current_time, std::chrono::seconds{INVENTORY_BROADCAST_INTERVAL >> 1}); @@ -4323,11 +4598,7 @@ bool PeerManager::SendMessages(CNode* pto) if (fSendTrickle && pto->m_tx_relay->fSendMempool) { auto vtxinfo = m_mempool.infoAll(); pto->m_tx_relay->fSendMempool = false; - CFeeRate filterrate; - { - LOCK(pto->m_tx_relay->cs_feeFilter); - filterrate = CFeeRate(pto->m_tx_relay->minFeeFilter); - } + const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()}; LOCK(pto->m_tx_relay->cs_filter); @@ -4361,11 +4632,7 @@ bool PeerManager::SendMessages(CNode* pto) for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) { vInvTx.push_back(it); } - CFeeRate filterrate; - { - LOCK(pto->m_tx_relay->cs_feeFilter); - filterrate = CFeeRate(pto->m_tx_relay->minFeeFilter); - } + const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()}; // Topologically and fee-rate sort the inventory we send for privacy and priority reasons. // A heap is used so that not all items need sorting if only a few are being sent. CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, state.m_wtxid_relay); @@ -4405,7 +4672,7 @@ bool PeerManager::SendMessages(CNode* pto) nRelayedTransactions++; { // Expire old relay messages - while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow) + while (!vRelayExpiration.empty() && vRelayExpiration.front().first < count_microseconds(current_time)) { mapRelay.erase(vRelayExpiration.front().second); vRelayExpiration.pop_front(); @@ -4413,12 +4680,12 @@ bool PeerManager::SendMessages(CNode* pto) auto ret = mapRelay.emplace(txid, std::move(txinfo.tx)); if (ret.second) { - vRelayExpiration.emplace_back(nNow + std::chrono::microseconds{RELAY_TX_CACHE_TIME}.count(), ret.first); + vRelayExpiration.emplace_back(count_microseconds(current_time + std::chrono::microseconds{RELAY_TX_CACHE_TIME}), ret.first); } // Add wtxid-based lookup into mapRelay as well, so that peers can request by wtxid auto ret2 = mapRelay.emplace(wtxid, ret.first->second); if (ret2.second) { - vRelayExpiration.emplace_back(nNow + std::chrono::microseconds{RELAY_TX_CACHE_TIME}.count(), ret2.first); + vRelayExpiration.emplace_back(count_microseconds(current_time + std::chrono::microseconds{RELAY_TX_CACHE_TIME}), ret2.first); } } if (vInv.size() == MAX_INV_SZ) { @@ -4443,10 +4710,7 @@ bool PeerManager::SendMessages(CNode* pto) // Detect whether we're stalling current_time = GetTime<std::chrono::microseconds>(); - // nNow is the current system time (GetTimeMicros is not mockable) and - // should be replaced by the mockable current_time eventually - nNow = GetTimeMicros(); - if (state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { + if (state.nStallingSince && state.nStallingSince < count_microseconds(current_time) - 1000000 * BLOCK_STALLING_TIMEOUT) { // Stalling only triggers when the block download window cannot move. During normal steady state, // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection // should only happen during initial block download. @@ -4462,7 +4726,7 @@ bool PeerManager::SendMessages(CNode* pto) if (state.vBlocksInFlight.size() > 0) { QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); - if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { + if (count_microseconds(current_time) > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->GetId()); pto->fDisconnect = true; return true; @@ -4472,7 +4736,7 @@ bool PeerManager::SendMessages(CNode* pto) if (state.fSyncStarted && state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) { // Detect whether this is a stalling initial-headers-sync peer if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24 * 60 * 60) { - if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) { + if (count_microseconds(current_time) > state.nHeadersSyncTimeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) { // Disconnect a peer (without the noban permission) if it is our only sync peer, // and we have others we could be using instead. // Note: If all our peers are inbound, then we won't @@ -4522,76 +4786,35 @@ bool PeerManager::SendMessages(CNode* pto) } if (state.nBlocksInFlight == 0 && staller != -1) { if (State(staller)->nStallingSince == 0) { - State(staller)->nStallingSince = nNow; + State(staller)->nStallingSince = count_microseconds(current_time); LogPrint(BCLog::NET, "Stall started peer=%d\n", staller); } } } // - // Message: getdata (non-blocks) + // Message: getdata (transactions) // - - // For robustness, expire old requests after a long timeout, so that - // we can resume downloading transactions from a peer even if they - // were unresponsive in the past. - // Eventually we should consider disconnecting peers, but this is - // conservative. - if (state.m_tx_download.m_check_expiry_timer <= current_time) { - for (auto it=state.m_tx_download.m_tx_in_flight.begin(); it != state.m_tx_download.m_tx_in_flight.end();) { - if (it->second <= current_time - TX_EXPIRY_INTERVAL) { - LogPrint(BCLog::NET, "timeout of inflight tx %s from peer=%d\n", it->first.ToString(), pto->GetId()); - state.m_tx_download.m_tx_announced.erase(it->first); - state.m_tx_download.m_tx_in_flight.erase(it++); - } else { - ++it; - } - } - // On average, we do this check every TX_EXPIRY_INTERVAL. Randomize - // so that we're not doing this for all peers at the same time. - state.m_tx_download.m_check_expiry_timer = current_time + TX_EXPIRY_INTERVAL / 2 + GetRandMicros(TX_EXPIRY_INTERVAL); - } - - auto& tx_process_time = state.m_tx_download.m_tx_process_time; - while (!tx_process_time.empty() && tx_process_time.begin()->first <= current_time && state.m_tx_download.m_tx_in_flight.size() < MAX_PEER_TX_IN_FLIGHT) { - const GenTxid gtxid = tx_process_time.begin()->second; - // Erase this entry from tx_process_time (it may be added back for - // processing at a later time, see below) - tx_process_time.erase(tx_process_time.begin()); - CInv inv(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*pto)), gtxid.GetHash()); - if (!AlreadyHaveTx(ToGenTxid(inv), m_mempool)) { - // If this transaction was last requested more than 1 minute ago, - // then request. - const auto last_request_time = GetTxRequestTime(gtxid); - if (last_request_time <= current_time - GETDATA_TX_INTERVAL) { - LogPrint(BCLog::NET, "Requesting %s peer=%d\n", inv.ToString(), pto->GetId()); - vGetData.push_back(inv); - if (vGetData.size() >= MAX_GETDATA_SZ) { - m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); - vGetData.clear(); - } - UpdateTxRequestTime(gtxid, current_time); - state.m_tx_download.m_tx_in_flight.emplace(gtxid.GetHash(), current_time); - } else { - // This transaction is in flight from someone else; queue - // up processing to happen after the download times out - // (with a slight delay for inbound peers, to prefer - // requests to outbound peers). - // Don't apply the txid-delay to re-requests of a - // transaction; the heuristic of delaying requests to - // txid-relay peers is to save bandwidth on initial - // announcement of a transaction, and doesn't make sense - // for a followup request if our first peer times out (and - // would open us up to an attacker using inbound - // wtxid-relay to prevent us from requesting transactions - // from outbound txid-relay peers). - const auto next_process_time = CalculateTxGetDataTime(gtxid, current_time, !state.fPreferredDownload, false); - tx_process_time.emplace(next_process_time, gtxid); + std::vector<std::pair<NodeId, GenTxid>> expired; + auto requestable = m_txrequest.GetRequestable(pto->GetId(), current_time, &expired); + for (const auto& entry : expired) { + LogPrint(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", entry.second.IsWtxid() ? "wtx" : "tx", + entry.second.GetHash().ToString(), entry.first); + } + for (const GenTxid& gtxid : requestable) { + if (!AlreadyHaveTx(gtxid, m_mempool)) { + LogPrint(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", + gtxid.GetHash().ToString(), pto->GetId()); + vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*pto)), gtxid.GetHash()); + if (vGetData.size() >= MAX_GETDATA_SZ) { + m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData)); + vGetData.clear(); } + m_txrequest.RequestedTx(pto->GetId(), gtxid.GetHash(), current_time + GETDATA_TX_INTERVAL); } else { - // We have already seen this transaction, no need to download. - state.m_tx_download.m_tx_announced.erase(gtxid.GetHash()); - state.m_tx_download.m_tx_in_flight.erase(gtxid.GetHash()); + // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as + // this should already be called whenever a transaction becomes AlreadyHaveTx(). + m_txrequest.ForgetTxHash(gtxid.GetHash()); } } @@ -4606,7 +4829,6 @@ bool PeerManager::SendMessages(CNode* pto) !pto->HasPermission(PF_FORCERELAY) // peers with the forcerelay permission should not filter txs to us ) { CAmount currentFilter = m_mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); - int64_t timeNow = GetTimeMicros(); static FeeFilterRounder g_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}}; if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) { // Received tx-inv messages are discarded when the active @@ -4617,10 +4839,10 @@ bool PeerManager::SendMessages(CNode* pto) if (pto->m_tx_relay->lastSentFeeFilter == MAX_FILTER) { // Send the current filter if we sent MAX_FILTER previously // and made it out of IBD. - pto->m_tx_relay->nextSendTimeFeeFilter = timeNow - 1; + pto->m_tx_relay->nextSendTimeFeeFilter = count_microseconds(current_time) - 1; } } - if (timeNow > pto->m_tx_relay->nextSendTimeFeeFilter) { + if (count_microseconds(current_time) > pto->m_tx_relay->nextSendTimeFeeFilter) { CAmount filterToSend = g_filter_rounder.round(currentFilter); // We always have a fee filter of at least minRelayTxFee filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); @@ -4628,13 +4850,13 @@ bool PeerManager::SendMessages(CNode* pto) m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); pto->m_tx_relay->lastSentFeeFilter = filterToSend; } - pto->m_tx_relay->nextSendTimeFeeFilter = PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); + pto->m_tx_relay->nextSendTimeFeeFilter = PoissonNextSend(count_microseconds(current_time), AVG_FEEFILTER_BROADCAST_INTERVAL); } // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. - else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->m_tx_relay->nextSendTimeFeeFilter && + else if (count_microseconds(current_time) + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->m_tx_relay->nextSendTimeFeeFilter && (currentFilter < 3 * pto->m_tx_relay->lastSentFeeFilter / 4 || currentFilter > 4 * pto->m_tx_relay->lastSentFeeFilter / 3)) { - pto->m_tx_relay->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000; + pto->m_tx_relay->nextSendTimeFeeFilter = count_microseconds(current_time) + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000; } } } // release cs_main diff --git a/src/net_processing.h b/src/net_processing.h index 3e748c0c5b..eaa3b142a8 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -6,18 +6,13 @@ #ifndef BITCOIN_NET_PROCESSING_H #define BITCOIN_NET_PROCESSING_H -#include <consensus/params.h> #include <net.h> #include <sync.h> #include <validationinterface.h> -class BlockTransactionsRequest; -class BlockValidationState; -class CBlockHeader; class CChainParams; class CTxMemPool; class ChainstateManager; -class TxValidationState; extern RecursiveMutex cs_main; extern RecursiveMutex g_cs_orphans; @@ -31,123 +26,48 @@ static const bool DEFAULT_PEERBLOCKFILTERS = false; /** Threshold for marking a node to be discouraged, e.g. disconnected and added to the discouragement filter. */ static const int DISCOURAGEMENT_THRESHOLD{100}; -class PeerManager final : public CValidationInterface, public NetEventsInterface { -public: - PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman, - CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool); +struct CNodeStateStats { + int nSyncHeight = -1; + int nCommonHeight = -1; + int m_starting_height = -1; + std::vector<int> vHeightInFlight; +}; - /** - * Overridden from CValidationInterface. - */ - void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override; - void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override; - /** - * Overridden from CValidationInterface. - */ - void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override; - /** - * Overridden from CValidationInterface. - */ - void BlockChecked(const CBlock& block, const BlockValidationState& state) override; - /** - * Overridden from CValidationInterface. - */ - void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override; +class PeerManager : public CValidationInterface, public NetEventsInterface +{ +public: + static std::unique_ptr<PeerManager> make(const CChainParams& chainparams, CConnman& connman, BanMan* banman, + CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool, + bool ignore_incoming_txs); + virtual ~PeerManager() { } - /** Initialize a peer by adding it to mapNodeState and pushing a message requesting its version */ - void InitializeNode(CNode* pnode) override; - /** Handle removal of a peer by updating various state and removing it from mapNodeState */ - void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override; - /** - * Process protocol messages received from a given node - * - * @param[in] pfrom The node which we have received messages from. - * @param[in] interrupt Interrupt condition for processing threads - */ - bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override; - /** - * Send queued protocol messages to be sent to a give node. - * - * @param[in] pto The node which we are sending messages to. - * @return True if there is more work to be done - */ - bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing); + /** Get statistics from node state */ + virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) = 0; - /** Consider evicting an outbound peer based on the amount of time they've been behind our tip */ - void ConsiderEviction(CNode& pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - /** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */ - void CheckForStaleTipAndEvictPeers(); - /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */ - void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - /** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */ - void ReattemptInitialBroadcast(CScheduler& scheduler) const; + /** Whether this node ignores txs received over p2p. */ + virtual bool IgnoresIncomingTxs() = 0; - /** Process a single message from a peer. Public for fuzz testing */ - void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, - const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc); + /** Set the best height */ + virtual void SetBestHeight(int height) = 0; /** * Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node * to be discouraged, meaning the peer might be disconnected and added to the discouragement filter. * Public for unit testing. */ - void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message); + virtual void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) = 0; -private: /** - * Potentially mark a node discouraged based on the contents of a BlockValidationState object - * - * @param[in] via_compact_block this bool is passed in because net_processing should - * punish peers differently depending on whether the data was provided in a compact - * block message or not. If the compact block had a valid header, but contained invalid - * txs, the peer should not be punished. See BIP 152. - * - * @return Returns true if the peer was punished (probably disconnected) - */ - bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, - bool via_compact_block, const std::string& message = ""); - - /** - * Potentially disconnect and discourage a node based on the contents of a TxValidationState object - * - * @return Returns true if the peer was punished (probably disconnected) - */ - bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = ""); - - /** Maybe disconnect a peer and discourage future connections from its address. - * - * @param[in] pnode The node to check. - * @return True if the peer was marked for disconnection in this function + * Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound. + * Public for unit testing. */ - bool MaybeDiscourageAndDisconnect(CNode& pnode); - - void ProcessOrphanTx(std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn) - EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans); - /** Process a single headers message from a peer. */ - void ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHeader>& headers, bool via_compact_block); - - void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req); - - const CChainParams& m_chainparams; - CConnman& m_connman; - /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */ - BanMan* const m_banman; - ChainstateManager& m_chainman; - CTxMemPool& m_mempool; + virtual void CheckForStaleTipAndEvictPeers() = 0; - int64_t m_stale_tip_check_time; //!< Next time to check for stale tip -}; - -struct CNodeStateStats { - int m_misbehavior_score = 0; - int nSyncHeight = -1; - int nCommonHeight = -1; - std::vector<int> vHeightInFlight; + /** Process a single message from a peer. Public for fuzz testing */ + virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv, + const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) = 0; }; -/** Get statistics from node state */ -bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); - /** Relay transaction to every node */ void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main); diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 08714dc2ec..85e46fd373 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -255,10 +255,14 @@ bool CNetAddr::SetSpecial(const std::string& str) Span<const uint8_t> input_checksum{input.data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN}; Span<const uint8_t> input_version{input.data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)}; + if (input_version != torv3::VERSION) { + return false; + } + uint8_t calculated_checksum[torv3::CHECKSUM_LEN]; torv3::Checksum(input_pubkey, calculated_checksum); - if (input_checksum != calculated_checksum || input_version != torv3::VERSION) { + if (input_checksum != calculated_checksum) { return false; } @@ -281,7 +285,7 @@ CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope) { SetLegacyIPv6(Span<const uint8_t>(reinterpret_cast<const uint8_t*>(&ipv6Addr), sizeof(ipv6Addr))); - scopeId = scope; + m_scope_id = scope; } bool CNetAddr::IsBindAny() const @@ -433,6 +437,11 @@ bool CNetAddr::IsValid() const return false; } + // CJDNS addresses always start with 0xfc + if (IsCJDNS() && (m_addr[0] != 0xFC)) { + return false; + } + // documentation IPv6 address if (IsRFC3849()) return false; @@ -474,6 +483,26 @@ bool CNetAddr::IsInternal() const return m_net == NET_INTERNAL; } +bool CNetAddr::IsAddrV1Compatible() const +{ + switch (m_net) { + case NET_IPV4: + case NET_IPV6: + case NET_INTERNAL: + return true; + case NET_ONION: + return m_addr.size() == ADDR_TORV2_SIZE; + case NET_I2P: + case NET_CJDNS: + return false; + case NET_UNROUTABLE: // m_net is never and should not be set to NET_UNROUTABLE + case NET_MAX: // m_net is never and should not be set to NET_MAX + assert(false); + } // no default case, so the compiler can warn about missing cases + + assert(false); +} + enum Network CNetAddr::GetNetwork() const { if (IsInternal()) @@ -629,7 +658,7 @@ uint32_t CNetAddr::GetLinkedIPv4() const assert(false); } -uint32_t CNetAddr::GetNetClass() const +Network CNetAddr::GetNetClass() const { // Make sure that if we return NET_IPV6, then IsIPv6() is true. The callers expect that. @@ -744,9 +773,12 @@ std::vector<unsigned char> CNetAddr::GetGroup(const std::vector<bool> &asmap) co std::vector<unsigned char> CNetAddr::GetAddrBytes() const { - uint8_t serialized[V1_SERIALIZATION_SIZE]; - SerializeV1Array(serialized); - return {std::begin(serialized), std::end(serialized)}; + if (IsAddrV1Compatible()) { + uint8_t serialized[V1_SERIALIZATION_SIZE]; + SerializeV1Array(serialized); + return {std::begin(serialized), std::end(serialized)}; + } + return std::vector<unsigned char>(m_addr.begin(), m_addr.end()); } uint64_t CNetAddr::GetHash() const @@ -918,7 +950,7 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const memset(paddrin6, 0, *addrlen); if (!GetIn6Addr(&paddrin6->sin6_addr)) return false; - paddrin6->sin6_scope_id = scopeId; + paddrin6->sin6_scope_id = m_scope_id; paddrin6->sin6_family = AF_INET6; paddrin6->sin6_port = htons(port); return true; @@ -1036,15 +1068,24 @@ CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet() CSubNet::CSubNet(const CNetAddr& addr) : CSubNet() { - valid = addr.IsIPv4() || addr.IsIPv6(); - if (!valid) { + switch (addr.m_net) { + case NET_IPV4: + case NET_IPV6: + valid = true; + assert(addr.m_addr.size() <= sizeof(netmask)); + memset(netmask, 0xFF, addr.m_addr.size()); + break; + case NET_ONION: + case NET_I2P: + case NET_CJDNS: + valid = true; + break; + case NET_INTERNAL: + case NET_UNROUTABLE: + case NET_MAX: return; } - assert(addr.m_addr.size() <= sizeof(netmask)); - - memset(netmask, 0xFF, addr.m_addr.size()); - network = addr; } @@ -1056,6 +1097,21 @@ bool CSubNet::Match(const CNetAddr &addr) const { if (!valid || !addr.IsValid() || network.m_net != addr.m_net) return false; + + switch (network.m_net) { + case NET_IPV4: + case NET_IPV6: + break; + case NET_ONION: + case NET_I2P: + case NET_CJDNS: + case NET_INTERNAL: + return addr == network; + case NET_UNROUTABLE: + case NET_MAX: + return false; + } + assert(network.m_addr.size() == addr.m_addr.size()); for (size_t x = 0; x < addr.m_addr.size(); ++x) { if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) { @@ -1067,18 +1123,35 @@ bool CSubNet::Match(const CNetAddr &addr) const std::string CSubNet::ToString() const { - assert(network.m_addr.size() <= sizeof(netmask)); + std::string suffix; - uint8_t cidr = 0; + switch (network.m_net) { + case NET_IPV4: + case NET_IPV6: { + assert(network.m_addr.size() <= sizeof(netmask)); - for (size_t i = 0; i < network.m_addr.size(); ++i) { - if (netmask[i] == 0x00) { - break; + uint8_t cidr = 0; + + for (size_t i = 0; i < network.m_addr.size(); ++i) { + if (netmask[i] == 0x00) { + break; + } + cidr += NetmaskBits(netmask[i]); } - cidr += NetmaskBits(netmask[i]); + + suffix = strprintf("/%u", cidr); + break; + } + case NET_ONION: + case NET_I2P: + case NET_CJDNS: + case NET_INTERNAL: + case NET_UNROUTABLE: + case NET_MAX: + break; } - return network.ToString() + strprintf("/%u", cidr); + return network.ToString() + suffix; } bool CSubNet::IsValid() const @@ -1086,6 +1159,29 @@ bool CSubNet::IsValid() const return valid; } +bool CSubNet::SanityCheck() const +{ + switch (network.m_net) { + case NET_IPV4: + case NET_IPV6: + break; + case NET_ONION: + case NET_I2P: + case NET_CJDNS: + return true; + case NET_INTERNAL: + case NET_UNROUTABLE: + case NET_MAX: + return false; + } + + for (size_t x = 0; x < network.m_addr.size(); ++x) { + if (network.m_addr[x] & ~netmask[x]) return false; + } + + return true; +} + bool operator==(const CSubNet& a, const CSubNet& b) { return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16); diff --git a/src/netaddress.h b/src/netaddress.h index 59f1b87ad3..b9eade7fd5 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -29,7 +29,7 @@ * Make sure that this does not collide with any of the values in `version.h` * or with `SERIALIZE_TRANSACTION_NO_WITNESS`. */ -static const int ADDRV2_FORMAT = 0x20000000; +static constexpr int ADDRV2_FORMAT = 0x20000000; /** * A network type. @@ -130,7 +130,11 @@ class CNetAddr */ Network m_net{NET_IPV6}; - uint32_t scopeId{0}; // for scoped/link-local ipv6 addresses + /** + * Scope id if scoped/link-local IPV6 address. + * See https://tools.ietf.org/html/rfc4007 + */ + uint32_t m_scope_id{0}; public: CNetAddr(); @@ -173,12 +177,18 @@ class CNetAddr bool IsRoutable() const; bool IsInternal() const; bool IsValid() const; + + /** + * Check if the current object can be serialized in pre-ADDRv2/BIP155 format. + */ + bool IsAddrV1Compatible() const; + enum Network GetNetwork() const; std::string ToString() const; std::string ToStringIP() const; uint64_t GetHash() const; bool GetInAddr(struct in_addr* pipv4Addr) const; - uint32_t GetNetClass() const; + Network GetNetClass() const; //! For IPv4, mapped IPv4, SIIT translated IPv4, Teredo, 6to4 tunneled addresses, return the relevant IPv4 address as a uint32. uint32_t GetLinkedIPv4() const; @@ -202,6 +212,14 @@ class CNetAddr friend bool operator<(const CNetAddr& a, const CNetAddr& b); /** + * Whether this address should be relayed to other peers even if we can't reach it ourselves. + */ + bool IsRelayable() const + { + return IsIPv4() || IsIPv6() || IsTor(); + } + + /** * Serialize to a stream. */ template <typename Stream> @@ -388,7 +406,7 @@ class CNetAddr "Address too long: %u > %u", address_size, MAX_ADDRV2_SIZE)); } - scopeId = 0; + m_scope_id = 0; if (SetNetFromBIP155Network(bip155_net, address_size)) { m_addr.resize(address_size); @@ -441,12 +459,36 @@ class CSubNet /// Is this value valid? (only used to signal parse errors) bool valid; + bool SanityCheck() const; + public: + /** + * Construct an invalid subnet (empty, `Match()` always returns false). + */ CSubNet(); + + /** + * Construct from a given network start and number of bits (CIDR mask). + * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is + * created. + * @param[in] mask CIDR mask, must be in [0, 32] for IPv4 addresses and in [0, 128] for + * IPv6 addresses. Otherwise an invalid subnet is created. + */ CSubNet(const CNetAddr& addr, uint8_t mask); + + /** + * Construct from a given network start and mask. + * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is + * created. + * @param[in] mask Network mask, must be of the same type as `addr` and not contain 0-bits + * followed by 1-bits. Otherwise an invalid subnet is created. + */ CSubNet(const CNetAddr& addr, const CNetAddr& mask); - //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128) + /** + * Construct a single-host subnet. + * @param[in] addr The sole address to be contained in the subnet, can also be non-IPv[46]. + */ explicit CSubNet(const CNetAddr& addr); bool Match(const CNetAddr &addr) const; @@ -458,7 +500,23 @@ class CSubNet friend bool operator!=(const CSubNet& a, const CSubNet& b) { return !(a == b); } friend bool operator<(const CSubNet& a, const CSubNet& b); - SERIALIZE_METHODS(CSubNet, obj) { READWRITE(obj.network, obj.netmask, obj.valid); } + SERIALIZE_METHODS(CSubNet, obj) + { + READWRITE(obj.network); + if (obj.network.IsIPv4()) { + // Before commit 102867c587f5f7954232fb8ed8e85cda78bb4d32, CSubNet used the last 4 bytes of netmask + // to store the relevant bytes for an IPv4 mask. For compatibility reasons, keep doing so in + // serialized form. + unsigned char dummy[12] = {0}; + READWRITE(dummy); + READWRITE(MakeSpan(obj.netmask).first(4)); + } else { + READWRITE(obj.netmask); + } + READWRITE(obj.valid); + // Mark invalid if the result doesn't pass sanity checking. + SER_READ(obj, if (obj.valid) obj.valid = obj.SanityCheck()); + } }; /** A combination of a network address (CNetAddr) and a (TCP) port */ diff --git a/src/netbase.cpp b/src/netbase.cpp index 0273839017..264029d8a2 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -52,14 +52,20 @@ enum Network ParseNetwork(const std::string& net_in) { return NET_UNROUTABLE; } -std::string GetNetworkName(enum Network net) { - switch(net) - { +std::string GetNetworkName(enum Network net) +{ + switch (net) { + case NET_UNROUTABLE: return "unroutable"; case NET_IPV4: return "ipv4"; case NET_IPV6: return "ipv6"; case NET_ONION: return "onion"; - default: return ""; - } + case NET_I2P: return "i2p"; + case NET_CJDNS: return "cjdns"; + case NET_INTERNAL: return "internal"; + case NET_MAX: assert(false); + } // no default case, so the compiler can warn about missing cases + + assert(false); } bool static LookupIntern(const std::string& name, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h index ffb3fe2f29..89fb4758f9 100644 --- a/src/netmessagemaker.h +++ b/src/netmessagemaker.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp index fb46ea1731..02e50c4dbe 100644 --- a/src/node/coinstats.cpp +++ b/src/node/coinstats.cpp @@ -112,7 +112,7 @@ bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, CoinStatsHashType hash_t } // The legacy hash serializes the hashBlock -static void PrepareHash(CHashWriter& ss, CCoinsStats& stats) +static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats) { ss << stats.hashBlock; } diff --git a/src/node/coinstats.h b/src/node/coinstats.h index 2a7441c10e..7c56bfc2ad 100644 --- a/src/node/coinstats.h +++ b/src/node/coinstats.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/node/context.cpp b/src/node/context.cpp index 49d0c37235..958221a913 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -8,6 +8,7 @@ #include <interfaces/chain.h> #include <net.h> #include <net_processing.h> +#include <policy/fees.h> #include <scheduler.h> #include <txmempool.h> diff --git a/src/node/context.h b/src/node/context.h index 3228831ed1..9b611bf8f5 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -12,6 +12,7 @@ class ArgsManager; class BanMan; +class CBlockPolicyEstimator; class CConnman; class CScheduler; class CTxMemPool; @@ -36,6 +37,7 @@ class WalletClient; struct NodeContext { std::unique_ptr<CConnman> connman; std::unique_ptr<CTxMemPool> mempool; + std::unique_ptr<CBlockPolicyEstimator> fee_estimator; std::unique_ptr<PeerManager> peerman; ChainstateManager* chainman{nullptr}; // Currently a raw pointer because the memory is not managed by this struct std::unique_ptr<BanMan> banman; diff --git a/src/interfaces/chain.cpp b/src/node/interfaces.cpp index 4c5ebe66fc..e07eaa33d8 100644 --- a/src/interfaces/chain.cpp +++ b/src/node/interfaces.cpp @@ -2,18 +2,26 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <interfaces/chain.h> - +#include <addrdb.h> +#include <banman.h> +#include <boost/signals2/signal.hpp> #include <chain.h> #include <chainparams.h> +#include <init.h> +#include <interfaces/chain.h> #include <interfaces/handler.h> +#include <interfaces/node.h> #include <interfaces/wallet.h> +#include <mapport.h> #include <net.h> #include <net_processing.h> +#include <netaddress.h> +#include <netbase.h> #include <node/coin.h> #include <node/context.h> #include <node/transaction.h> #include <node/ui_interface.h> +#include <policy/feerate.h> #include <policy/fees.h> #include <policy/policy.h> #include <policy/rbf.h> @@ -23,22 +31,274 @@ #include <rpc/protocol.h> #include <rpc/server.h> #include <shutdown.h> +#include <support/allocators/secure.h> #include <sync.h> #include <timedata.h> #include <txmempool.h> #include <uint256.h> #include <univalue.h> +#include <util/check.h> +#include <util/ref.h> #include <util/system.h> +#include <util/translation.h> #include <validation.h> #include <validationinterface.h> +#include <warnings.h> + +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif #include <memory> #include <utility> -namespace interfaces { +using interfaces::BlockTip; +using interfaces::Chain; +using interfaces::FoundBlock; +using interfaces::Handler; +using interfaces::MakeHandler; +using interfaces::Node; +using interfaces::WalletClient; + +namespace node { namespace { +class NodeImpl : public Node +{ +public: + explicit NodeImpl(NodeContext* context) { setContext(context); } + void initLogging() override { InitLogging(*Assert(m_context->args)); } + void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); } + bilingual_str getWarnings() override { return GetWarnings(true); } + uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); } + bool baseInitialize() override + { + return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() && + AppInitLockDataDirectory() && AppInitInterfaces(*m_context); + } + bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override + { + return AppInitMain(m_context_ref, *m_context, tip_info); + } + void appShutdown() override + { + Interrupt(*m_context); + Shutdown(*m_context); + } + void startShutdown() override + { + StartShutdown(); + // Stop RPC for clean shutdown if any of waitfor* commands is executed. + if (gArgs.GetBoolArg("-server", false)) { + InterruptRPC(); + StopRPC(); + } + } + bool shutdownRequested() override { return ShutdownRequested(); } + void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); } + bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); } + size_t getNodeCount(CConnman::NumConnections flags) override + { + return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0; + } + bool getNodesStats(NodesStats& stats) override + { + stats.clear(); + + if (m_context->connman) { + std::vector<CNodeStats> stats_temp; + m_context->connman->GetNodeStats(stats_temp); + + stats.reserve(stats_temp.size()); + for (auto& node_stats_temp : stats_temp) { + stats.emplace_back(std::move(node_stats_temp), false, CNodeStateStats()); + } + + // Try to retrieve the CNodeStateStats for each node. + if (m_context->peerman) { + TRY_LOCK(::cs_main, lockMain); + if (lockMain) { + for (auto& node_stats : stats) { + std::get<1>(node_stats) = + m_context->peerman->GetNodeStateStats(std::get<0>(node_stats).nodeid, std::get<2>(node_stats)); + } + } + } + return true; + } + return false; + } + bool getBanned(banmap_t& banmap) override + { + if (m_context->banman) { + m_context->banman->GetBanned(banmap); + return true; + } + return false; + } + bool ban(const CNetAddr& net_addr, int64_t ban_time_offset) override + { + if (m_context->banman) { + m_context->banman->Ban(net_addr, ban_time_offset); + return true; + } + return false; + } + bool unban(const CSubNet& ip) override + { + if (m_context->banman) { + m_context->banman->Unban(ip); + return true; + } + return false; + } + bool disconnectByAddress(const CNetAddr& net_addr) override + { + if (m_context->connman) { + return m_context->connman->DisconnectNode(net_addr); + } + return false; + } + bool disconnectById(NodeId id) override + { + if (m_context->connman) { + return m_context->connman->DisconnectNode(id); + } + return false; + } + int64_t getTotalBytesRecv() override { return m_context->connman ? m_context->connman->GetTotalBytesRecv() : 0; } + int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; } + size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; } + size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; } + bool getHeaderTip(int& height, int64_t& block_time) override + { + LOCK(::cs_main); + if (::pindexBestHeader) { + height = ::pindexBestHeader->nHeight; + block_time = ::pindexBestHeader->GetBlockTime(); + return true; + } + return false; + } + int getNumBlocks() override + { + LOCK(::cs_main); + return ::ChainActive().Height(); + } + uint256 getBestBlockHash() override + { + const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip()); + return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash(); + } + int64_t getLastBlockTime() override + { + LOCK(::cs_main); + if (::ChainActive().Tip()) { + return ::ChainActive().Tip()->GetBlockTime(); + } + return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network + } + double getVerificationProgress() override + { + const CBlockIndex* tip; + { + LOCK(::cs_main); + tip = ::ChainActive().Tip(); + } + return GuessVerificationProgress(Params().TxData(), tip); + } + bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); } + bool getReindex() override { return ::fReindex; } + bool getImporting() override { return ::fImporting; } + void setNetworkActive(bool active) override + { + if (m_context->connman) { + m_context->connman->SetNetworkActive(active); + } + } + bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); } + CFeeRate getDustRelayFee() override { return ::dustRelayFee; } + UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override + { + JSONRPCRequest req(m_context_ref); + req.params = params; + req.strMethod = command; + req.URI = uri; + return ::tableRPC.execute(req); + } + std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); } + void rpcSetTimerInterfaceIfUnset(RPCTimerInterface* iface) override { RPCSetTimerInterfaceIfUnset(iface); } + void rpcUnsetTimerInterface(RPCTimerInterface* iface) override { RPCUnsetTimerInterface(iface); } + bool getUnspentOutput(const COutPoint& output, Coin& coin) override + { + LOCK(::cs_main); + return ::ChainstateActive().CoinsTip().GetCoin(output, coin); + } + WalletClient& walletClient() override + { + return *Assert(m_context->wallet_client); + } + std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override + { + return MakeHandler(::uiInterface.InitMessage_connect(fn)); + } + std::unique_ptr<Handler> handleMessageBox(MessageBoxFn fn) override + { + return MakeHandler(::uiInterface.ThreadSafeMessageBox_connect(fn)); + } + std::unique_ptr<Handler> handleQuestion(QuestionFn fn) override + { + return MakeHandler(::uiInterface.ThreadSafeQuestion_connect(fn)); + } + std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override + { + return MakeHandler(::uiInterface.ShowProgress_connect(fn)); + } + std::unique_ptr<Handler> handleNotifyNumConnectionsChanged(NotifyNumConnectionsChangedFn fn) override + { + return MakeHandler(::uiInterface.NotifyNumConnectionsChanged_connect(fn)); + } + std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) override + { + return MakeHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn)); + } + std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override + { + return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn)); + } + std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override + { + return MakeHandler(::uiInterface.BannedListChanged_connect(fn)); + } + std::unique_ptr<Handler> handleNotifyBlockTip(NotifyBlockTipFn fn) override + { + return MakeHandler(::uiInterface.NotifyBlockTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { + fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()}, + GuessVerificationProgress(Params().TxData(), block)); + })); + } + std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) override + { + return MakeHandler( + ::uiInterface.NotifyHeaderTip_connect([fn](SynchronizationState sync_state, const CBlockIndex* block) { + fn(sync_state, BlockTip{block->nHeight, block->GetBlockTime(), block->GetBlockHash()}, + /* verification progress is unused when a header was received */ 0); + })); + } + NodeContext* context() override { return m_context; } + void setContext(NodeContext* context) override + { + m_context = context; + if (context) { + m_context_ref.Set(*context); + } else { + m_context_ref.Clear(); + } + } + NodeContext* m_context{nullptr}; + util::Ref m_context_ref; +}; -bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock) +bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active) { if (!index) return false; if (block.m_hash) *block.m_hash = index->GetBlockHash(); @@ -46,6 +306,8 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec if (block.m_time) *block.m_time = index->GetBlockTime(); if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax(); if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast(); + if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index; + if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active); if (block.m_data) { REVERSE_LOCK(lock); if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) block.m_data->SetNull(); @@ -148,48 +410,33 @@ public: Optional<int> getHeight() override { LOCK(::cs_main); - int height = ::ChainActive().Height(); + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + int height = active.Height(); if (height >= 0) { return height; } return nullopt; } - Optional<int> getBlockHeight(const uint256& hash) override - { - LOCK(::cs_main); - CBlockIndex* block = LookupBlockIndex(hash); - if (block && ::ChainActive().Contains(block)) { - return block->nHeight; - } - return nullopt; - } uint256 getBlockHash(int height) override { LOCK(::cs_main); - CBlockIndex* block = ::ChainActive()[height]; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + CBlockIndex* block = active[height]; assert(block); return block->GetBlockHash(); } bool haveBlockOnDisk(int height) override { LOCK(cs_main); - CBlockIndex* block = ::ChainActive()[height]; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + CBlockIndex* block = active[height]; return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; } - Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override - { - LOCK(cs_main); - CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height); - if (block) { - if (hash) *hash = block->GetBlockHash(); - return block->nHeight; - } - return nullopt; - } CBlockLocator getTipLocator() override { LOCK(cs_main); - return ::ChainActive().GetLocator(); + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + return active.GetLocator(); } bool checkFinalTx(const CTransaction& tx) override { @@ -199,7 +446,8 @@ public: Optional<int> findLocatorFork(const CBlockLocator& locator) override { LOCK(cs_main); - if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) { + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + if (CBlockIndex* fork = FindForkInGlobalIndex(active, locator)) { return fork->nHeight; } return nullopt; @@ -207,47 +455,45 @@ public: bool findBlock(const uint256& hash, const FoundBlock& block) override { WAIT_LOCK(cs_main, lock); - return FillBlock(LookupBlockIndex(hash), block, lock); + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + return FillBlock(LookupBlockIndex(hash), block, lock, active); } bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override { WAIT_LOCK(cs_main, lock); - return FillBlock(ChainActive().FindEarliestAtLeast(min_time, min_height), block, lock); - } - bool findNextBlock(const uint256& block_hash, int block_height, const FoundBlock& next, bool* reorg) override { - WAIT_LOCK(cs_main, lock); - CBlockIndex* block = ChainActive()[block_height]; - if (block && block->GetBlockHash() != block_hash) block = nullptr; - if (reorg) *reorg = !block; - return FillBlock(block ? ChainActive()[block_height + 1] : nullptr, next, lock); + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active); } bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override { WAIT_LOCK(cs_main, lock); + const CChain& active = Assert(m_node.chainman)->ActiveChain(); if (const CBlockIndex* block = LookupBlockIndex(block_hash)) { if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) { - return FillBlock(ancestor, ancestor_out, lock); + return FillBlock(ancestor, ancestor_out, lock, active); } } - return FillBlock(nullptr, ancestor_out, lock); + return FillBlock(nullptr, ancestor_out, lock, active); } bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override { WAIT_LOCK(cs_main, lock); + const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CBlockIndex* block = LookupBlockIndex(block_hash); const CBlockIndex* ancestor = LookupBlockIndex(ancestor_hash); if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr; - return FillBlock(ancestor, ancestor_out, lock); + return FillBlock(ancestor, ancestor_out, lock, active); } bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override { WAIT_LOCK(cs_main, lock); + const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CBlockIndex* block1 = LookupBlockIndex(block_hash1); const CBlockIndex* block2 = LookupBlockIndex(block_hash2); const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr; // Using & instead of && below to avoid short circuiting and leaving // output uninitialized. - return FillBlock(ancestor, ancestor_out, lock) & FillBlock(block1, block1_out, lock) & FillBlock(block2, block2_out, lock); + return FillBlock(ancestor, ancestor_out, lock, active) & FillBlock(block1, block1_out, lock, active) & FillBlock(block2, block2_out, lock, active); } void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); } double guessVerificationProgress(const uint256& block_hash) override @@ -327,11 +573,13 @@ public: } CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override { - return ::feeEstimator.estimateSmartFee(num_blocks, calc, conservative); + if (!m_node.fee_estimator) return {}; + return m_node.fee_estimator->estimateSmartFee(num_blocks, calc, conservative); } unsigned int estimateMaxBlocks() override { - return ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); + if (!m_node.fee_estimator) return 0; + return m_node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); } CFeeRate mempoolMinFee() override { @@ -365,7 +613,8 @@ public: { if (!old_tip.IsNull()) { LOCK(::cs_main); - if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); + if (old_tip == active.Tip()->GetBlockHash()) return; } SyncWithValidationInterfaceQueue(); } @@ -411,7 +660,9 @@ public: NodeContext& m_node; }; } // namespace +} // namespace node -std::unique_ptr<Chain> MakeChain(NodeContext& node) { return MakeUnique<ChainImpl>(node); } - +namespace interfaces { +std::unique_ptr<Node> MakeNode(NodeContext* context) { return MakeUnique<node::NodeImpl>(context); } +std::unique_ptr<Chain> MakeChain(NodeContext& context) { return MakeUnique<node::ChainImpl>(context); } } // namespace interfaces diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 9ae4700743..d3bb9687a8 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,6 +13,19 @@ #include <future> +static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out) +{ + err_string_out = state.ToString(); + if (state.IsInvalid()) { + if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { + return TransactionError::MISSING_INPUTS; + } + return TransactionError::MEMPOOL_REJECTED; + } else { + return TransactionError::MEMPOOL_ERROR; + } +} + TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback) { // BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs. @@ -36,20 +49,24 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t if (!existingCoin.IsSpent()) return TransactionError::ALREADY_IN_CHAIN; } if (!node.mempool->exists(hashTx)) { - // Transaction is not already in the mempool. Submit it. + // Transaction is not already in the mempool. TxValidationState state; - if (!AcceptToMemoryPool(*node.mempool, state, tx, - nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) { - err_string = state.ToString(); - if (state.IsInvalid()) { - if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { - return TransactionError::MISSING_INPUTS; - } - return TransactionError::MEMPOOL_REJECTED; - } else { - return TransactionError::MEMPOOL_ERROR; + if (max_tx_fee > 0) { + // First, call ATMP with test_accept and check the fee. If ATMP + // fails here, return error immediately. + CAmount fee{0}; + if (!AcceptToMemoryPool(*node.mempool, state, tx, + nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee)) { + return HandleATMPError(state, err_string); + } else if (fee > max_tx_fee) { + return TransactionError::MAX_FEE_EXCEEDED; } } + // Try to submit the transaction to the mempool. + if (!AcceptToMemoryPool(*node.mempool, state, tx, + nullptr /* plTxnReplaced */, false /* bypass_limits */)) { + return HandleATMPError(state, err_string); + } // Transaction was accepted to the mempool. diff --git a/src/node/transaction.h b/src/node/transaction.h index 6491700d44..0c016ff04e 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -36,6 +36,6 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10}; * @param[in] wait_callback wait until callbacks have been processed to avoid stale result due to a sequentially RPC. * return error */ -NODISCARD TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback); +[[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback); #endif // BITCOIN_NODE_TRANSACTION_H diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h index c8b4d60fd0..fe78cb46bd 100644 --- a/src/node/utxo_snapshot.h +++ b/src/node/utxo_snapshot.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/noui.cpp b/src/noui.cpp index 3c82512fac..6fe5c5638c 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/noui.h b/src/noui.h index 8ec5708328..cf273ffb33 100644 --- a/src/noui.h +++ b/src/noui.h @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2019 The Bitcoin Core developers +// Copyright (c) 2013-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/optional.h b/src/optional.h index a382cd7b77..583c56eabd 100644 --- a/src/optional.h +++ b/src/optional.h @@ -1,26 +1,20 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_OPTIONAL_H #define BITCOIN_OPTIONAL_H +#include <optional> #include <utility> -#include <boost/optional.hpp> - //! Substitute for C++17 std::optional +//! DEPRECATED use std::optional in new code. 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)); -} +using Optional = std::optional<T>; //! Substitute for C++17 std::nullopt -static auto& nullopt = boost::none; +//! DEPRECATED use std::nullopt in new code. +static auto& nullopt = std::nullopt; #endif // BITCOIN_OPTIONAL_H diff --git a/src/outputtype.cpp b/src/outputtype.cpp index e978852826..d96fb282c5 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -19,8 +19,6 @@ static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy"; static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit"; static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32"; -const std::array<OutputType, 3> OUTPUT_TYPES = {OutputType::LEGACY, OutputType::P2SH_SEGWIT, OutputType::BECH32}; - bool ParseOutputType(const std::string& type, OutputType& output_type) { if (type == OUTPUT_TYPE_STRING_LEGACY) { diff --git a/src/outputtype.h b/src/outputtype.h index 77a16b1d05..88422e5824 100644 --- a/src/outputtype.h +++ b/src/outputtype.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,9 +20,13 @@ enum class OutputType { BECH32, }; -extern const std::array<OutputType, 3> OUTPUT_TYPES; +static constexpr auto OUTPUT_TYPES = std::array{ + OutputType::LEGACY, + OutputType::P2SH_SEGWIT, + OutputType::BECH32, +}; -NODISCARD bool ParseOutputType(const std::string& str, OutputType& output_type); +[[nodiscard]] bool ParseOutputType(const std::string& str, OutputType& output_type); const std::string& FormatOutputType(OutputType type); /** diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp index a01e259731..3da85fedf9 100644 --- a/src/policy/feerate.cpp +++ b/src/policy/feerate.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -38,7 +38,7 @@ CAmount CFeeRate::GetFee(size_t nBytes_) const std::string CFeeRate::ToString(const FeeEstimateMode& fee_estimate_mode) const { switch (fee_estimate_mode) { - case FeeEstimateMode::SAT_B: return strprintf("%d.%03d %s/B", nSatoshisPerK / 1000, nSatoshisPerK % 1000, CURRENCY_ATOM); - default: return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT); + case FeeEstimateMode::SAT_VB: return strprintf("%d.%03d %s/vB", nSatoshisPerK / 1000, nSatoshisPerK % 1000, CURRENCY_ATOM); + default: return strprintf("%d.%08d %s/kvB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT); } } diff --git a/src/policy/feerate.h b/src/policy/feerate.h index 883940f73c..86ae507957 100644 --- a/src/policy/feerate.h +++ b/src/policy/feerate.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,8 +19,8 @@ enum class FeeEstimateMode { UNSET, //!< Use default settings based on other criteria ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates - BTC_KB, //!< Use explicit BTC/kB fee given in coin control - SAT_B, //!< Use explicit sat/B fee given in coin control + BTC_KVB, //!< Use BTC/kvB fee rate unit + SAT_VB, //!< Use sat/vB fee rate unit }; /** @@ -39,7 +39,16 @@ public: // We've previously had bugs creep in from silent double->int conversion... static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats"); } - /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/ + /** Constructor for a fee rate in satoshis per kvB (sat/kvB). The size in bytes must not exceed (2^63 - 1). + * + * Passing an nBytes value of COIN (1e8) returns a fee rate in satoshis per vB (sat/vB), + * e.g. (nFeePaid * 1e8 / 1e3) == (nFeePaid / 1e5), + * where 1e5 is the ratio to convert from BTC/kvB to sat/vB. + * + * @param[in] nFeePaid CAmount fee rate to construct with + * @param[in] nBytes size_t bytes (units) to construct with + * @returns fee rate + */ CFeeRate(const CAmount& nFeePaid, size_t nBytes); /** * Return the fee in satoshis for the given size in bytes. @@ -56,7 +65,7 @@ public: friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; } friend bool operator!=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK != b.nSatoshisPerK; } CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; } - std::string ToString(const FeeEstimateMode& fee_estimate_mode = FeeEstimateMode::BTC_KB) const; + std::string ToString(const FeeEstimateMode& fee_estimate_mode = FeeEstimateMode::BTC_KVB) const; SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); } }; diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 0f31093dbb..7da171d2e1 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -1,28 +1,29 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <policy/fees.h> #include <clientversion.h> +#include <fs.h> +#include <logging.h> #include <streams.h> #include <txmempool.h> #include <util/system.h> -static constexpr double INF_FEERATE = 1e99; - -std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) { - static const std::map<FeeEstimateHorizon, std::string> horizon_strings = { - {FeeEstimateHorizon::SHORT_HALFLIFE, "short"}, - {FeeEstimateHorizon::MED_HALFLIFE, "medium"}, - {FeeEstimateHorizon::LONG_HALFLIFE, "long"}, - }; - auto horizon_string = horizon_strings.find(horizon); +static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat"; - if (horizon_string == horizon_strings.end()) return "unknown"; +static constexpr double INF_FEERATE = 1e99; - return horizon_string->second; +std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) +{ + switch (horizon) { + case FeeEstimateHorizon::SHORT_HALFLIFE: return "short"; + case FeeEstimateHorizon::MED_HALFLIFE: return "medium"; + case FeeEstimateHorizon::LONG_HALFLIFE: return "long"; + } // no default case, so the compiler can warn about missing cases + assert(false); } /** @@ -489,6 +490,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator() { static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero"); size_t bucketIndex = 0; + for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) { buckets.push_back(bucketBoundary); bucketMap[bucketBoundary] = bucketIndex; @@ -500,6 +502,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator() feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE)); shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE)); longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE)); + + // If the fee estimation file is present, read recorded estimations + fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME; + CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION); + if (est_file.IsNull() || !Read(est_file)) { + LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", est_filepath.string()); + } } CBlockPolicyEstimator::~CBlockPolicyEstimator() @@ -632,7 +641,7 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const { - TxConfirmStats* stats; + TxConfirmStats* stats = nullptr; double sufficientTxs = SUFFICIENT_FEETXS; switch (horizon) { case FeeEstimateHorizon::SHORT_HALFLIFE: { @@ -648,10 +657,8 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr stats = longStats.get(); break; } - default: { - throw std::out_of_range("CBlockPolicyEstimator::estimateRawFee unknown FeeEstimateHorizon"); - } - } + } // no default case, so the compiler can warn about missing cases + assert(stats); LOCK(m_cs_fee_estimator); // Return failure if trying to analyze a target we're not tracking @@ -681,10 +688,8 @@ unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon hori case FeeEstimateHorizon::LONG_HALFLIFE: { return longStats->GetMaxConfirms(); } - default: { - throw std::out_of_range("CBlockPolicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon"); - } - } + } // no default case, so the compiler can warn about missing cases + assert(false); } unsigned int CBlockPolicyEstimator::BlockSpan() const @@ -856,6 +861,15 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation return CFeeRate(llround(median)); } +void CBlockPolicyEstimator::Flush() { + FlushUnconfirmed(); + + fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME; + CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION); + if (est_file.IsNull() || !Write(est_file)) { + LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", est_filepath.string()); + } +} bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const { @@ -888,8 +902,9 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein) LOCK(m_cs_fee_estimator); int nVersionRequired, nVersionThatWrote; filein >> nVersionRequired >> nVersionThatWrote; - if (nVersionRequired > CLIENT_VERSION) - return error("CBlockPolicyEstimator::Read(): up-version (%d) fee estimate file", nVersionRequired); + if (nVersionRequired > CLIENT_VERSION) { + throw std::runtime_error(strprintf("up-version (%d) fee estimate file", nVersionRequired)); + } // Read fee estimates file into temporary variables so existing data // structures aren't corrupted if there is an exception. @@ -907,8 +922,9 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein) std::vector<double> fileBuckets; filein >> fileBuckets; size_t numBuckets = fileBuckets.size(); - if (numBuckets <= 1 || numBuckets > 1000) + if (numBuckets <= 1 || numBuckets > 1000) { throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets"); + } std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE)); std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE)); diff --git a/src/policy/fees.h b/src/policy/fees.h index 8ea8816dc3..c444d71a31 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -11,6 +11,7 @@ #include <random.h> #include <sync.h> +#include <array> #include <map> #include <memory> #include <string> @@ -25,9 +26,15 @@ class TxConfirmStats; /* Identifier for each of the 3 different TxConfirmStats which will track * history over different time horizons. */ enum class FeeEstimateHorizon { - SHORT_HALFLIFE = 0, - MED_HALFLIFE = 1, - LONG_HALFLIFE = 2 + SHORT_HALFLIFE, + MED_HALFLIFE, + LONG_HALFLIFE, +}; + +static constexpr auto ALL_FEE_ESTIMATE_HORIZONS = std::array{ + FeeEstimateHorizon::SHORT_HALFLIFE, + FeeEstimateHorizon::MED_HALFLIFE, + FeeEstimateHorizon::LONG_HALFLIFE, }; std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon); @@ -215,6 +222,9 @@ public: /** Calculation of highest target that estimates are tracked for */ unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const; + /** Drop still unconfirmed transactions and record current estimations, if the fee estimation file is present. */ + void Flush(); + private: mutable RecursiveMutex m_cs_fee_estimator; diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 0e9820da1e..2b5fd4179d 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,7 +9,7 @@ #include <consensus/validation.h> #include <coins.h> - +#include <span.h> CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn) { @@ -75,7 +75,7 @@ bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType) bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason) { - if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) { + if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) { reason = "version"; return false; } @@ -92,14 +92,15 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR for (const CTxIn& txin : tx.vin) { - // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed - // keys (remember the 520 byte limit on redeemScript size). That works - // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 - // bytes of scriptSig, which we round off to 1650 bytes for some minor - // future-proofing. That's also enough to spend a 20-of-20 - // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not - // considered standard. - if (txin.scriptSig.size() > 1650) { + // Biggest 'standard' txin involving only keys is a 15-of-15 P2SH + // multisig with compressed keys (remember the 520 byte limit on + // redeemScript size). That works out to a (15*(33+1))+3=513 byte + // redeemScript, 513+1+15*(73+1)+3=1627 bytes of scriptSig, which + // we round off to 1650(MAX_STANDARD_SCRIPTSIG_SIZE) bytes for + // some minor future-proofing. That's also enough to spend a + // 20-of-20 CHECKMULTISIG scriptPubKey, though such a scriptPubKey + // is not considered standard. + if (txin.scriptSig.size() > MAX_STANDARD_SCRIPTSIG_SIZE) { reason = "scriptsig-size"; return false; } @@ -155,7 +156,7 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR * * Note that only the non-witness portion of the transaction is checked here. */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active) { if (tx.IsCoinBase()) return true; // Coinbases don't use vin normally @@ -183,6 +184,9 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) { return false; } + } else if (whichType == TxoutType::WITNESS_V1_TAPROOT) { + // Don't allow Taproot spends unless Taproot is active. + if (!taproot_active) return false; } } @@ -206,6 +210,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) // get the scriptPubKey corresponding to this input: CScript prevScript = prev.scriptPubKey; + bool p2sh = false; if (prevScript.IsPayToScriptHash()) { std::vector <std::vector<unsigned char> > stack; // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig @@ -216,6 +221,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) if (stack.empty()) return false; prevScript = CScript(stack.back().begin(), stack.back().end()); + p2sh = true; } int witnessversion = 0; @@ -237,6 +243,36 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) return false; } } + + // Check policy limits for Taproot spends: + // - MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE limit for stack item size + // - No annexes + if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && !p2sh) { + // Taproot spend (non-P2SH-wrapped, version 1, witness program size 32; see BIP 341) + auto stack = MakeSpan(tx.vin[i].scriptWitness.stack); + if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) { + // Annexes are nonstandard as long as no semantics are defined for them. + return false; + } + if (stack.size() >= 2) { + // Script path spend (2 or more stack elements after removing optional annex) + const auto& control_block = SpanPopBack(stack); + SpanPopBack(stack); // Ignore script + if (control_block.empty()) return false; // Empty control block is invalid + if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) { + // Leaf version 0xc0 (aka Tapscript, see BIP 342) + for (const auto& item : stack) { + if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) return false; + } + } + } else if (stack.size() == 1) { + // Key path spend (1 stack element after removing optional annex) + // (no policy rules apply) + } else { + // 0 stack elements; this is already invalid by consensus rules + return false; + } + } } return true; } diff --git a/src/policy/policy.h b/src/policy/policy.h index 7f168ee20f..f2a3f35546 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -38,10 +38,14 @@ static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; static const bool DEFAULT_PERMIT_BAREMULTISIG = true; /** The maximum number of witness stack items in a standard P2WSH script */ static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100; -/** The maximum size of each witness stack item in a standard P2WSH script */ +/** The maximum size in bytes of each witness stack item in a standard P2WSH script */ static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80; -/** The maximum size of a standard witnessScript */ +/** The maximum size in bytes of each witness stack item in a standard BIP 342 script (Taproot, leaf version 0xc0) */ +static const unsigned int MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE = 80; +/** The maximum size in bytes of a standard witnessScript */ static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600; +/** The maximum size of a standard ScriptSig */ +static const unsigned int MAX_STANDARD_SCRIPTSIG_SIZE = 1650; /** Min feerate for defining dust. Historically this has been based on the * minRelayTxFee, however changing the dust limit changes which transactions are * standard and should be done with care and ideally rarely. It makes sense to @@ -68,7 +72,11 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE | - SCRIPT_VERIFY_CONST_SCRIPTCODE; + SCRIPT_VERIFY_CONST_SCRIPTCODE | + SCRIPT_VERIFY_TAPROOT | + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION | + SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS | + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE; /** For convenience, standard but not mandatory verify flags. */ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; @@ -82,22 +90,32 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee); bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee); bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType); - /** - * Check for standard transaction types - * @return True if all outputs (scriptPubKeys) use only standard transaction forms - */ + + +// Changing the default transaction version requires a two step process: first +// adapting relay policy by bumping TX_MAX_STANDARD_VERSION, and then later +// allowing the new transaction version in the wallet/RPC. +static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2}; + +/** +* Check for standard transaction types +* @return True if all outputs (scriptPubKeys) use only standard transaction forms +*/ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason); - /** - * Check for standard transaction types - * @param[in] mapInputs Map of previous transactions that have outputs we're spending - * @return True if all inputs (scriptSigs) use only standard transaction forms - */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); - /** - * Check if the transaction is over standard P2WSH resources limit: - * 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements - * These limits are adequate for multi-signature up to n-of-100 using OP_CHECKSIG, OP_ADD, and OP_EQUAL, - */ +/** +* Check for standard transaction types +* @param[in] mapInputs Map of previous transactions that have outputs we're spending +* @param[in] taproot_active Whether or taproot consensus rules are active (used to decide whether spends of them are permitted) +* @return True if all inputs (scriptSigs) use only standard transaction forms +*/ +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active); +/** +* Check if the transaction is over standard P2WSH resources limit: +* 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements +* These limits are adequate for multisignatures up to n-of-100 using OP_CHECKSIG, OP_ADD, and OP_EQUAL. +* +* Also enforce a maximum stack item size limit and no annexes for tapscript spends. +*/ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); /** Compute the virtual transaction size (weight reinterpreted as bytes). */ diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp index 4b55934891..8125b41c41 100644 --- a/src/policy/rbf.cpp +++ b/src/policy/rbf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/policy/rbf.h b/src/policy/rbf.h index f84e6e5286..e078070c1c 100644 --- a/src/policy/rbf.h +++ b/src/policy/rbf.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/block.h b/src/primitives/block.h index fd8fc8b868..2d10853607 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index e6183cf2f4..245206b906 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -77,8 +77,6 @@ uint256 CTransaction::ComputeWitnessHash() const return SerializeHash(*this, SER_GETHASH, 0); } -/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */ -CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash{}, m_witness_hash{} {} CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {} diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 77cb1781a4..6bf36ee854 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -262,12 +262,6 @@ public: // Default transaction version. static const int32_t CURRENT_VERSION=2; - // Changing the default transaction version requires a two step process: first - // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date - // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and - // MAX_STANDARD_VERSION will be equal. - static const int32_t MAX_STANDARD_VERSION=2; - // The local variables are made const to prevent unintended modification // without updating the cached hash value. However, CTransaction is not // actually immutable; deserialization and assignment are implemented, @@ -287,12 +281,9 @@ private: uint256 ComputeWitnessHash() const; public: - /** Construct a CTransaction that qualifies as IsNull() */ - CTransaction(); - /** Convert a CMutableTransaction into a CTransaction. */ - explicit CTransaction(const CMutableTransaction &tx); - CTransaction(CMutableTransaction &&tx); + explicit CTransaction(const CMutableTransaction& tx); + CTransaction(CMutableTransaction&& tx); template <typename Stream> inline void Serialize(Stream& s) const { @@ -393,14 +384,13 @@ struct CMutableTransaction }; typedef std::shared_ptr<const CTransaction> CTransactionRef; -static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); } template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); } /** A generic txid reference (txid or wtxid). */ class GenTxid { - const bool m_is_wtxid; - const uint256 m_hash; + bool m_is_wtxid; + uint256 m_hash; public: GenTxid(bool is_wtxid, const uint256& hash) : m_is_wtxid(is_wtxid), m_hash(hash) {} bool IsWtxid() const { return m_is_wtxid; } diff --git a/src/protocol.cpp b/src/protocol.cpp index 84b6e96aee..56e738eaa8 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,6 +14,8 @@ namespace NetMsgType { const char *VERSION="version"; const char *VERACK="verack"; const char *ADDR="addr"; +const char *ADDRV2="addrv2"; +const char *SENDADDRV2="sendaddrv2"; const char *INV="inv"; const char *GETDATA="getdata"; const char *MERKLEBLOCK="merkleblock"; @@ -52,6 +54,8 @@ const static std::string allNetMessageTypes[] = { NetMsgType::VERSION, NetMsgType::VERACK, NetMsgType::ADDR, + NetMsgType::ADDRV2, + NetMsgType::SENDADDRV2, NetMsgType::INV, NetMsgType::GETDATA, NetMsgType::MERKLEBLOCK, @@ -199,7 +203,6 @@ static std::string serviceFlagToStr(size_t bit) switch ((ServiceFlags)service_flag) { case NODE_NONE: abort(); // impossible case NODE_NETWORK: return "NETWORK"; - case NODE_GETUTXO: return "GETUTXO"; case NODE_BLOOM: return "BLOOM"; case NODE_WITNESS: return "WITNESS"; case NODE_COMPACT_FILTERS: return "COMPACT_FILTERS"; diff --git a/src/protocol.h b/src/protocol.h index 9a44a1626c..f183db0501 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -77,6 +77,18 @@ extern const char* VERACK; */ extern const char* ADDR; /** + * The addrv2 message relays connection information for peers on the network just + * like the addr message, but is extended to allow gossiping of longer node + * addresses (see BIP155). + */ +extern const char *ADDRV2; +/** + * The sendaddrv2 message signals support for receiving ADDRV2 messages (BIP155). + * It also implies that its sender can encode as ADDRV2 and would send ADDRV2 + * instead of ADDR to a peer that has signaled ADDRV2 support by sending SENDADDRV2. + */ +extern const char *SENDADDRV2; +/** * The inv message (inventory message) transmits one or more inventories of * objects known to the transmitting peer. */ @@ -261,10 +273,6 @@ enum ServiceFlags : uint64_t { // NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently // set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients. NODE_NETWORK = (1 << 0), - // NODE_GETUTXO means the node is capable of responding to the getutxo protocol request. - // Bitcoin Core does not support this but a patch set called Bitcoin XT does. - // See BIP 64 for details on how this is implemented. - NODE_GETUTXO = (1 << 1), // NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections. // Bitcoin Core nodes used to support this by default, without advertising this bit, // but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION) @@ -351,7 +359,8 @@ class CAddress : public CService public: CAddress() : CService{} {}; - explicit CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {}; + CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {}; + CAddress(CService ipIn, ServiceFlags nServicesIn, uint32_t nTimeIn) : CService{ipIn}, nTime{nTimeIn}, nServices{nServicesIn} {}; SERIALIZE_METHODS(CAddress, obj) { @@ -370,7 +379,14 @@ public: // nTime. READWRITE(obj.nTime); } - READWRITE(Using<CustomUintFormatter<8>>(obj.nServices)); + if (nVersion & ADDRV2_FORMAT) { + uint64_t services_tmp; + SER_WRITE(obj, services_tmp = obj.nServices); + READWRITE(Using<CompactSizeFormatter<false>>(services_tmp)); + SER_READ(obj, obj.nServices = static_cast<ServiceFlags>(services_tmp)); + } else { + READWRITE(Using<CustomUintFormatter<8>>(obj.nServices)); + } READWRITEAS(CService, obj); } diff --git a/src/psbt.cpp b/src/psbt.cpp index 3fb743e5db..4db57d3cd0 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -3,6 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <psbt.h> + +#include <util/check.h> #include <util/strencodings.h> @@ -207,7 +209,8 @@ size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) { void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index) { - const CTxOut& out = psbt.tx->vout.at(index); + CMutableTransaction& tx = *Assert(psbt.tx); + const CTxOut& out = tx.vout.at(index); PSBTOutput& psbt_out = psbt.outputs.at(index); // Fill a SignatureData with output info @@ -217,7 +220,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio // Construct a would-be spend of this output, to update sigdata with. // Note that ProduceSignature is used to fill in metadata (not actual signatures), // so provider does not need to provide any private keys (it can be a HidingSigningProvider). - MutableTransactionSignatureCreator creator(psbt.tx.get_ptr(), /* index */ 0, out.nValue, SIGHASH_ALL); + MutableTransactionSignatureCreator creator(&tx, /* index */ 0, out.nValue, SIGHASH_ALL); ProduceSignature(provider, creator, out.scriptPubKey, sigdata); // Put redeem_script, witness_script, key paths, into PSBTOutput. diff --git a/src/psbt.h b/src/psbt.h index 0951b76f83..b566726ee3 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -398,7 +398,7 @@ struct PartiallySignedTransaction /** Merge psbt into this. The two psbts must have the same underlying CTransaction (i.e. the * same actual Bitcoin transaction.) Returns true if the merge succeeded, false otherwise. */ - NODISCARD bool Merge(const PartiallySignedTransaction& psbt); + [[nodiscard]] bool Merge(const PartiallySignedTransaction& psbt); bool AddInput(const CTxIn& txin, PSBTInput& psbtin); bool AddOutput(const CTxOut& txout, const PSBTOutput& psbtout); PartiallySignedTransaction() {} @@ -605,11 +605,11 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti * @param[in] psbtxs the PSBTs to combine * @return error (OK if we successfully combined the transactions, other error if they were not compatible) */ -NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs); +[[nodiscard]] TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs); //! Decode a base64ed PSBT into a PartiallySignedTransaction -NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error); +[[nodiscard]] bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error); //! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction -NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error); +[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error); #endif // BITCOIN_PSBT_H diff --git a/src/pubkey.cpp b/src/pubkey.cpp index fc14f41a0c..fc1624af25 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,7 @@ #include <secp256k1.h> #include <secp256k1_recovery.h> +#include <secp256k1_schnorrsig.h> namespace { @@ -166,6 +167,27 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_ return 1; } +XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes) +{ + assert(bytes.size() == 32); + std::copy(bytes.begin(), bytes.end(), m_keydata.begin()); +} + +bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const +{ + assert(sigbytes.size() == 64); + secp256k1_xonly_pubkey pubkey; + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &pubkey, m_keydata.data())) return false; + return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), &pubkey); +} + +bool XOnlyPubKey::CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const +{ + secp256k1_xonly_pubkey base_point; + if (!secp256k1_xonly_pubkey_parse(secp256k1_context_verify, &base_point, base.data())) return false; + return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_verify, m_keydata.begin(), parity, &base_point, hash.begin()); +} + bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const { if (!IsValid()) return false; diff --git a/src/pubkey.h b/src/pubkey.h index fcbc7e8416..12514fc3c9 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Copyright (c) 2017 The Zcash 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 <hash.h> #include <serialize.h> +#include <span.h> #include <uint256.h> #include <stdexcept> @@ -169,7 +170,16 @@ public: /* * Check syntactic correctness. * - * Note that this is consensus critical as CheckSig() calls it! + * When setting a pubkey (Set()) or deserializing fails (its header bytes + * don't match the length of the data), the size is set to 0. Thus, + * by checking size, one can observe whether Set() or deserialization has + * failed. + * + * This does not check for more than that. In particular, it does not verify + * that the coordinates correspond to a point on the curve (see IsFullyValid() + * for that instead). + * + * Note that this is consensus critical as CheckECDSASignature() calls it! */ bool IsValid() const { @@ -206,6 +216,27 @@ public: bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const; }; +class XOnlyPubKey +{ +private: + uint256 m_keydata; + +public: + /** Construct an x-only pubkey from exactly 32 bytes. */ + explicit XOnlyPubKey(Span<const unsigned char> bytes); + + /** Verify a Schnorr signature against this public key. + * + * sigbytes must be exactly 64 bytes. + */ + bool VerifySchnorr(const uint256& msg, Span<const unsigned char> sigbytes) const; + bool CheckPayToContract(const XOnlyPubKey& base, const uint256& hash, bool parity) const; + + const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); } + const unsigned char* data() const { return m_keydata.begin(); } + size_t size() const { return m_keydata.size(); } +}; + struct CExtPubKey { unsigned char nDepth; unsigned char vchFingerprint[4]; diff --git a/src/qt/README.md b/src/qt/README.md index 30c68db15b..20c712c98d 100644 --- a/src/qt/README.md +++ b/src/qt/README.md @@ -1,10 +1,12 @@ -This directory contains the BitcoinQT graphical user interface (GUI). It uses the cross-platform framework [Qt](https://www1.qt.io/developers/). +This directory contains the source code for the Bitcoin Core graphical user interface (GUI). It uses the [Qt](https://www1.qt.io/developers/) cross-platform framework. The current precise version for Qt 5 is specified in [qt.mk](/depends/packages/qt.mk). ## Compile and run -See build instructions ([macOS](/doc/build-osx.md), [Windows](/doc/build-windows.md), [Unix](/doc/build-unix.md), etc). +See build instructions: [Unix](/doc/build-unix.md), [macOS](/doc/build-osx.md), [Windows](/doc/build-windows.md), [FreeBSD](/doc/build-freebsd.md), [NetBSD](/doc/build-netbsd.md), [OpenBSD](/doc/build-openbsd.md) + +When following your systems build instructions, make sure to install the `Qt` dependencies. To run: @@ -12,84 +14,111 @@ To run: ./src/qt/bitcoin-qt ``` -## Files and directories - -### forms +## Files and Directories -Contains [Designer UI](https://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. They are created with [Qt Creator](#using-qt-creator-as-ide), but can be edited using any text editor. +#### forms/ -### locale +- A directory that contains [Designer UI](https://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. These files specify the characteristics of form elements in XML. Qt UI files can be edited with [Qt Creator](#using-qt-creator-as-ide) or using any text editor. -Contains translations. They are periodically updated. The process is described [here](/doc/translation_process.md). +#### locale/ -### res +- Contains translations. They are periodically updated and an effort is made to support as many languages as possible. The process of contributing translations is described in [doc/translation_process.md](/doc/translation_process.md). -Resources such as the icon. +#### res/ -### test + - Contains graphical resources used to enhance the UI experience. -Tests. +#### test/ -### bitcoingui.(h/cpp) +- Functional tests used to ensure proper functionality of the GUI. Significant changes to the GUI code normally require new or updated tests. -Represents the main window of the Bitcoin UI. +#### bitcoingui.(h/cpp) -### \*model.(h/cpp) +- Represents the main window of the Bitcoin UI. -The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](https://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other Qt classes like [QValidator](https://doc.qt.io/qt-5/qvalidator.html). +#### \*model.(h/cpp) -ClientModel is used by the main application `bitcoingui` and several models like `peertablemodel`. +- The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](https://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other Qt classes like [QValidator](https://doc.qt.io/qt-5/qvalidator.html). +- ClientModel is used by the main application `bitcoingui` and several models like `peertablemodel`. -### \*page.(h/cpp) +#### \*page.(h/cpp) -A controller. `:NAMEpage.cpp` generally includes `:NAMEmodel.h` and `forms/:NAME.page.ui` with a similar `:NAME`. +- A controller. `:NAMEpage.cpp` generally includes `:NAMEmodel.h` and `forms/:NAME.page.ui` with a similar `:NAME`. -### \*dialog.(h/cpp) +#### \*dialog.(h/cpp) -Various dialogs, e.g. to open a URL. Inherit from [QDialog](https://doc.qt.io/qt-5/qdialog.html). +- Various dialogs, e.g. to open a URL. Inherit from [QDialog](https://doc.qt.io/qt-5/qdialog.html). -### paymentserver.(h/cpp) +#### paymentserver.(h/cpp) -Used to process BIP21 payment URI requests. Also handles URI based application switching (e.g. when following a bitcoin:... link from a browser). +- (Deprecated) Used to process BIP21 payment URI requests. Also handles URI-based application switching (e.g. when following a bitcoin:... link from a browser). -### walletview.(h/cpp) +#### walletview.(h/cpp) -Represents the view to a single wallet. +- Represents the view to a single wallet. -### Other .h/cpp files +#### Other .h/cpp files * UI elements like BitcoinAmountField, which inherit from QWidget. * `bitcoinstrings.cpp`: automatically generated -* `bitcoinunits.(h/cpp)`: BTC / mBTC / etc handling +* `bitcoinunits.(h/cpp)`: BTC / mBTC / etc. handling * `callback.h` -* `guiconstants.h`: UI colors, app name, etc +* `guiconstants.h`: UI colors, app name, etc. * `guiutil.h`: several helper functions * `macdockiconhandler.(h/mm)`: macOS dock icon handler * `macnotificationhandler.(h/mm)`: display notifications in macOS ## Contribute -See [CONTRIBUTING.md](/CONTRIBUTING.md) for general guidelines. Specifically for Qt: +See [CONTRIBUTING.md](/CONTRIBUTING.md) for general guidelines. + +**Note:** Do not change `local/bitcoin_en.ts`. It is updated [automatically](/doc/translation_process.md#writing-code-with-translations). + +## Using Qt Creator as an IDE + +[Qt Creator](https://www.qt.io/product/development-tools) is a powerful tool which packages a UI designer tool (Qt Designer) and a C++ IDE into one application. This is especially useful if you want to change the UI layout. + +#### Download Qt Creator + +On Unix and macOS, Qt Creator can be installed through your package manager. Alternatively, you can download a binary from the [Qt Website](https://www.qt.io/download/). + +**Note:** If installing from a binary grabbed from the Qt Website: During the installation process, uncheck everything except for `Qt Creator`. + +##### macOS + +```sh +brew install qt-creator +``` + +##### Ubuntu & Debian + +```sh +sudo apt-get install qtcreator +``` + +#### Setup Qt Creator -* don't change `local/bitcoin_en.ts`; this happens [automatically](/doc/translation_process.md#writing-code-with-translations) +1. Make sure you've installed all dependencies specified in your systems build instructions +2. Follow the compile instructions for your system, run `./configure` with the `--enable-debug` flag +3. Start Qt Creator. At the start page, do: `New` -> `Import Project` -> `Import Existing Project` +4. Enter `bitcoin-qt` as the Project Name and enter the absolute path to `src/qt` as Location +5. Check over the file selection, you may need to select the `forms` directory (necessary if you intend to edit *.ui files) +6. Confirm the `Summary` page +7. In the `Projects` tab, select `Manage Kits...` -## Using Qt Creator as IDE + **macOS** + - Under `Kits`: select the default "Desktop" kit + - Under `Compilers`: select `"Clang (x86 64bit in /usr/bin)"` + - Under `Debuggers`: select `"LLDB"` as debugger (you might need to set the path to your LLDB installation) -You can use Qt Creator as an IDE. This is especially useful if you want to change -the UI layout. + **Ubuntu & Debian** -Download and install the community edition of [Qt Creator](https://www.qt.io/download/). -Uncheck everything except Qt Creator during the installation process. + Note: Some of these options may already be set -Instructions for macOS: + - Under `Kits`: select the default "Desktop" kit + - Under `Compilers`: select `"GCC (x86 64bit in /usr/bin)"` + - Under `Debuggers`: select `"GDB"` as debugger -1. Make sure you installed everything through Homebrew mentioned in the [macOS build instructions](/doc/build-osx.md) -2. Use `./configure` with the `--enable-debug` flag -3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project -4. Enter "bitcoin-qt" as project name, enter src/qt as location -5. Leave the file selection as it is -6. Confirm the "summary page" -7. In the "Projects" tab select "Manage Kits..." -8. Select the default "Desktop" kit and select "Clang (x86 64bit in /usr/bin)" as compiler -9. Select LLDB as debugger (you might need to set the path to your installation) -10. Start debugging with Qt Creator (you might need to the executable to "bitcoin-qt" under "Run", which is where you can also add command line arguments) +8. While in the `Projects` tab, ensure that you have the `bitcoin-qt` executable specified under `Run` + - If the executable is not specified: click `"Choose..."`, navigate to `src/qt`, and select `bitcoin-qt` +9. You're all set! Start developing, building, and debugging the Bitcoin Core GUI diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index aa4ec04497..ab6168a541 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -56,7 +56,7 @@ protected: }; AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::AddressBookPage), model(nullptr), mode(_mode), diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 3d303a6f68..c6a364ccbd 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 665c8e6053..bb444f22b3 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -11,7 +11,6 @@ #include <wallet/wallet.h> #include <algorithm> -#include <typeinfo> #include <QFont> #include <QDebug> @@ -82,8 +81,9 @@ public: { for (const auto& address : wallet.getAddresses()) { - if (pk_hash_only && address.dest.type() != typeid(PKHash)) + if (pk_hash_only && !std::holds_alternative<PKHash>(address.dest)) { continue; + } AddressTableEntry::Type addressType = translateTransactionType( QString::fromStdString(address.purpose), address.is_mine); cachedAddressTable.append(AddressTableEntry(addressType, @@ -177,13 +177,17 @@ AddressTableModel::~AddressTableModel() int AddressTableModel::rowCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return priv->size(); } int AddressTableModel::columnCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return columns.length(); } @@ -257,7 +261,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value, } else if(index.column() == Address) { CTxDestination newAddress = DecodeDestination(value.toString().toStdString()); // Refuse to set invalid address, set error status and return false - if(boost::get<CNoDestination>(&newAddress)) + if(std::get_if<CNoDestination>(&newAddress)) { editStatus = INVALID_ADDRESS; return false; diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 73316cadc4..6cc14654ef 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 3d1963b6e6..5b1330b81b 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,7 +20,7 @@ #include <QPushButton> AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureString* passphrase_out) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::AskPassphraseDialog), mode(_mode), model(nullptr), @@ -58,14 +58,6 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureStri ui->passEdit3->hide(); setWindowTitle(tr("Unlock wallet")); break; - case Decrypt: // Ask passphrase - ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet.")); - ui->passLabel2->hide(); - ui->passEdit2->hide(); - ui->passLabel3->hide(); - ui->passEdit3->hide(); - setWindowTitle(tr("Decrypt wallet")); - break; case ChangePass: // Ask old passphrase + new passphrase x2 setWindowTitle(tr("Change passphrase")); ui->warningLabel->setText(tr("Enter the old passphrase and new passphrase for the wallet.")); @@ -133,8 +125,7 @@ void AskPassphraseDialog::accept() "</b></qt>"); } else { assert(model != nullptr); - if(model->setWalletEncrypted(true, newpass1)) - { + if (model->setWalletEncrypted(newpass1)) { QMessageBox::warning(this, tr("Wallet encrypted"), "<qt>" + tr("Your wallet is now encrypted. ") + encryption_reminder + @@ -144,9 +135,7 @@ void AskPassphraseDialog::accept() "For security reasons, previous backups of the unencrypted wallet file " "will become useless as soon as you start using the new, encrypted wallet.") + "</b></qt>"); - } - else - { + } else { QMessageBox::critical(this, tr("Wallet encryption failed"), tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); } @@ -176,17 +165,6 @@ void AskPassphraseDialog::accept() QMessageBox::critical(this, tr("Wallet unlock failed"), e.what()); } break; - case Decrypt: - if(!model->setWalletEncrypted(false, oldpass)) - { - QMessageBox::critical(this, tr("Wallet decryption failed"), - tr("The passphrase entered for the wallet decryption was incorrect.")); - } - else - { - QDialog::accept(); // Success - } - break; case ChangePass: if(newpass1 == newpass2) { @@ -221,7 +199,6 @@ void AskPassphraseDialog::textChanged() acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty(); break; case Unlock: // Old passphrase x1 - case Decrypt: acceptable = !ui->passEdit1->text().isEmpty(); break; case ChangePass: // Old passphrase x1, new passphrase x2 diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index 9557e72936..66031b08d3 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -26,7 +26,6 @@ public: Encrypt, /**< Ask passphrase twice and encrypt */ Unlock, /**< Ask passphrase and unlock */ ChangePass, /**< Ask old passphrase + new passphrase twice */ - Decrypt /**< Ask passphrase and decrypt wallet */ }; explicit AskPassphraseDialog(Mode mode, QWidget *parent, SecureString* passphrase_out = nullptr); diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 2739b21a9d..a01a7bc386 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -11,6 +11,7 @@ #include <QDateTime> #include <QList> +#include <QLocale> #include <QModelIndex> #include <QVariant> @@ -97,13 +98,17 @@ BanTableModel::~BanTableModel() int BanTableModel::rowCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return priv->size(); } int BanTableModel::columnCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return columns.length(); } @@ -122,7 +127,7 @@ QVariant BanTableModel::data(const QModelIndex &index, int role) const case Bantime: QDateTime date = QDateTime::fromMSecsSinceEpoch(0); date = date.addSecs(rec->banEntry.nBanUntil); - return date.toString(Qt::SystemLocaleLongDate); + return QLocale::system().toString(date, QLocale::LongFormat); } } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 3055cd7da6..d6d5ba6968 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -51,6 +51,7 @@ #include <QThread> #include <QTimer> #include <QTranslator> +#include <QtGlobal> #if defined(QT_STATICPLUGIN) #include <QtPlugin> @@ -77,7 +78,7 @@ static void RegisterMetaTypes() #ifdef ENABLE_WALLET qRegisterMetaType<WalletModel*>(); #endif - // Register typedefs (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType) + // Register typedefs (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType) // IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1) qRegisterMetaType<CAmount>("CAmount"); qRegisterMetaType<size_t>("size_t"); @@ -263,7 +264,7 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { assert(!m_splash); - m_splash = new SplashScreen(nullptr, networkStyle); + m_splash = new SplashScreen(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. m_splash->show(); @@ -466,6 +467,13 @@ int GuiMain(int argc, char* argv[]) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif +#if (QT_VERSION <= QT_VERSION_CHECK(5, 9, 8)) && defined(Q_OS_MACOS) + const auto os_name = QSysInfo::prettyProductName(); + if (os_name.startsWith("macOS 11") || os_name.startsWith("macOS 10.16")) { + QApplication::setStyle("fusion"); + } +#endif + BitcoinApplication app; /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these @@ -505,6 +513,9 @@ int GuiMain(int argc, char* argv[]) return EXIT_SUCCESS; } + // Install global event filter that makes sure that long tooltips can be word-wrapped + app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); + /// 5. Now that settings and translations are available, ask user for data directory // User language is set up: pick a data directory bool did_show_intro = false; @@ -576,8 +587,6 @@ int GuiMain(int argc, char* argv[]) #endif // ENABLE_WALLET /// 9. Main GUI initialization - // Install global event filter that makes sure that long tooltips can be word-wrapped - app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); // Install global event filter that makes sure that out-of-focus labels do not contain text cursor. app.installEventFilter(new GUIUtil::LabelOutOfFocusEventFilter(&app)); #if defined(Q_OS_WIN) diff --git a/src/qt/bitcoin_locale.qrc b/src/qt/bitcoin_locale.qrc index a35ca15d62..a2f81c58e7 100644 --- a/src/qt/bitcoin_locale.qrc +++ b/src/qt/bitcoin_locale.qrc @@ -28,6 +28,7 @@ <file alias="fi">locale/bitcoin_fi.qm</file> <file alias="fil">locale/bitcoin_fil.qm</file> <file alias="fr">locale/bitcoin_fr.qm</file> + <file alias="gl_ES">locale/bitcoin_gl_ES.qm</file> <file alias="he">locale/bitcoin_he.qm</file> <file alias="hi">locale/bitcoin_hi.qm</file> <file alias="hr">locale/bitcoin_hr.qm</file> @@ -84,5 +85,6 @@ <file alias="zh_CN">locale/bitcoin_zh_CN.qm</file> <file alias="zh_HK">locale/bitcoin_zh_HK.qm</file> <file alias="zh_TW">locale/bitcoin_zh_TW.qm</file> + <file alias="zu">locale/bitcoin_zu.qm</file> </qresource> </RCC> diff --git a/src/qt/bitcoinaddressvalidator.h b/src/qt/bitcoinaddressvalidator.h index 52c06828a3..ae698c72a6 100644 --- a/src/qt/bitcoinaddressvalidator.h +++ b/src/qt/bitcoinaddressvalidator.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index a953c991bc..2af3502be3 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index d3e61aac29..c60d9a2c90 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 0c2dcc3584..ccc0a6828c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -30,6 +30,7 @@ #include <qt/macdockiconhandler.h> #endif +#include <functional> #include <chain.h> #include <chainparams.h> #include <interfaces/handler.h> @@ -615,10 +616,10 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH OptionsModel* optionsModel = _clientModel->getOptionsModel(); if (optionsModel && trayIcon) { // be aware of the tray icon disable state change reported by the OptionsModel object. - connect(optionsModel, &OptionsModel::hideTrayIconChanged, this, &BitcoinGUI::setTrayIconVisible); + connect(optionsModel, &OptionsModel::showTrayIconChanged, trayIcon, &QSystemTrayIcon::setVisible); // initialize the disable state of the tray icon with the current value in the model. - setTrayIconVisible(optionsModel->getHideTrayIcon()); + trayIcon->setVisible(optionsModel->getShowTrayIcon()); } } else { // Disable possibility to show main window via action @@ -669,14 +670,15 @@ void BitcoinGUI::addWallet(WalletModel* walletModel) { if (!walletFrame) return; if (!walletFrame->addWallet(walletModel)) return; - const QString display_name = walletModel->getDisplayName(); - setWalletActionsEnabled(true); rpcConsole->addWallet(walletModel); - m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); - if (m_wallet_selector->count() == 2) { + if (m_wallet_selector->count() == 0) { + setWalletActionsEnabled(true); + } else if (m_wallet_selector->count() == 1) { m_wallet_selector_label_action->setVisible(true); m_wallet_selector_action->setVisible(true); } + const QString display_name = walletModel->getDisplayName(); + m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); } void BitcoinGUI::removeWallet(WalletModel* walletModel) @@ -844,7 +846,7 @@ void BitcoinGUI::showDebugWindowActivateConsole() void BitcoinGUI::showHelpMessageClicked() { - helpMessageDialog->show(); + GUIUtil::bringToFront(helpMessageDialog); } #ifdef ENABLE_WALLET @@ -1310,7 +1312,7 @@ void BitcoinGUI::updateProxyIcon() bool proxy_enabled = clientModel->getProxyInfo(ip_port); if (proxy_enabled) { - if (labelProxyIcon->pixmap() == nullptr) { + if (!GUIUtil::HasPixmap(labelProxyIcon)) { 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)); @@ -1386,14 +1388,6 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress) } } -void BitcoinGUI::setTrayIconVisible(bool fHideTrayIcon) -{ - if (trayIcon) - { - trayIcon->setVisible(!fHideTrayIcon); - } -} - void BitcoinGUI::showModalOverlay() { if (modalOverlay && (progressBar->isVisible() || modalOverlay->isLayerVisible())) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 912297a74e..147f19e68d 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -49,6 +49,7 @@ struct BlockAndHeaderTipInfo; QT_BEGIN_NAMESPACE class QAction; class QComboBox; +class QDateTime; class QMenu; class QProgressBar; class QProgressDialog; @@ -317,9 +318,6 @@ public Q_SLOTS: /** Show progress dialog e.g. for verifychain */ void showProgress(const QString &title, int nProgress); - /** When hideTrayIcon setting is changed in OptionsModel hide or show the icon accordingly. */ - void setTrayIconVisible(bool); - void showModalOverlay(); }; diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 64900a4343..27e512d075 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -11,20 +11,19 @@ static const char UNUSED *bitcoin_strings[] = { QT_TRANSLATE_NOOP("bitcoin-core", "The %s developers"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring " +"a backup."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "-maxtxfee is set very high! Fees this large could be paid on a single " "transaction."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"Can't generate a change-address key. No keys in the internal keypool and " -"can't generate any keys."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot obtain a lock on data directory %s. %s is probably already running."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot provide specific connections and have addrman find outgoing " "connections at the same."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot upgrade a non HD split wallet without upgrading to support pre split " -"keypool. Please use -upgradewallet=169900 or -upgradewallet with no version " -"specified."), +"keypool. Please use version 169900 or no version specified."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Distributed under the MIT software license, see the accompanying file %s or " "%s"), @@ -40,6 +39,9 @@ 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", "" +"More than one onion bind address is provided. Using %s for the automatically " +"created Tor onion service."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Please check that your computer's date and time are correct! If your clock " "is wrong, %s will not work properly."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -51,6 +53,15 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Prune: last wallet synchronisation goes beyond pruned data. You need to -" "reindex (download the whole blockchain again in case of pruned node)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet " +"schema version: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"SQLiteDatabase: Failed to prepare the statement to fetch the application id: " +"%s"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is " +"supported"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. Only " "rebuild the block database if you are sure that your computer's date and " @@ -58,9 +69,16 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", "" "The transaction amount is too small to send after the fee has been deducted"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"This error could occur if this wallet was not shutdown cleanly and was last " +"loaded using a build with a newer version of Berkeley DB. If so, please use " +"the software that last loaded this wallet"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "This is a pre-release test build - use at your own risk - do not use for " "mining or merchant applications"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"This is the maximum transaction fee you pay (in addition to the normal fee) " +"to prioritize partial spend avoidance over regular coin selection."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "This is the transaction fee you may discard if change is smaller than dust " "at this level"), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -69,6 +87,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Total length of network version string (%i) exceeds maximum length (%i). " "Reduce the number or size of uacomments."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Transaction needs a change address, but we can't generate it. Please call " +"keypoolrefill first."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Unable to replay blocks. You will need to rebuild the database using -" "reindex-chainstate."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -80,21 +101,17 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: The network does not appear to fully agree! Some miners appear to " "be experiencing issues."), QT_TRANSLATE_NOOP("bitcoin-core", "" -"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."), -QT_TRANSLATE_NOOP("bitcoin-core", "" "Warning: We do not appear to fully agree with our peers! You may need to " "upgrade, or other nodes may need to upgrade."), QT_TRANSLATE_NOOP("bitcoin-core", "" "You need to rebuild the database using -reindex to go back to unpruned " "mode. This will redownload the entire blockchain"), -QT_TRANSLATE_NOOP("bitcoin-core", "%d of last 100 blocks have unexpected version"), -QT_TRANSLATE_NOOP("bitcoin-core", "%s corrupt, salvage failed"), QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"), QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"), +QT_TRANSLATE_NOOP("bitcoin-core", "A fatal internal error occurred, see debug.log for details"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot downgrade wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -peerblockfilters without -blockfilterindex."), 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."), @@ -102,6 +119,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Copyright (C) %i-%i"), QT_TRANSLATE_NOOP("bitcoin-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("bitcoin-core", "Could not find asmap file %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Could not parse asmap file %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "Disk space is too low!"), QT_TRANSLATE_NOOP("bitcoin-core", "Do you want to rebuild the block database now?"), QT_TRANSLATE_NOOP("bitcoin-core", "Done loading"), QT_TRANSLATE_NOOP("bitcoin-core", "Error initializing block database"), @@ -111,15 +129,16 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading %s: Private keys can only be di 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 block database"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet %s. Duplicate -wallet filename specified."), QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), 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: 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 too low!"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Keypool ran out, please call keypoolrefill first"), 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"), +QT_TRANSLATE_NOOP("bitcoin-core", "Failed to verify database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Fee rate (%s) is lower than the minimum fee rate setting (%s)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Ignoring duplicate -wallet %s."), QT_TRANSLATE_NOOP("bitcoin-core", "Importing..."), QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."), @@ -137,6 +156,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist..."), QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index..."), QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet..."), QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>."), QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."), QT_TRANSLATE_NOOP("bitcoin-core", "Prune cannot be configured with a negative value."), QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -blockfilterindex."), @@ -146,6 +166,12 @@ 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", "SQLiteDatabase: Failed to execute statement to verify database: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to fetch the application id: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to prepare statement to verify database: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Failed to read database verification error: %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "SQLiteDatabase: Unexpected application id. Expected %u, got %u"), 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"), @@ -184,5 +210,4 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks..."), QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet(s)..."), QT_TRANSLATE_NOOP("bitcoin-core", "Wallet needed to be rewritten: restart %s to complete"), QT_TRANSLATE_NOOP("bitcoin-core", "Warning: unknown new rules activated (versionbit %i)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Zapping all transactions from wallet..."), }; diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index fd55c547fc..9660ba99f7 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,6 +8,8 @@ #include <cassert> +static constexpr auto MAX_DIGITS_BTC = 16; + BitcoinUnits::BitcoinUnits(QObject *parent): QAbstractListModel(parent), unitlist(availableUnits()) @@ -108,7 +110,9 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator qint64 n_abs = (n > 0 ? n : -n); qint64 quotient = n_abs / coin; QString quotient_str = QString::number(quotient); - if (justify) quotient_str = quotient_str.rightJustified(16 - num_decimals, ' '); + if (justify) { + quotient_str = quotient_str.rightJustified(MAX_DIGITS_BTC - num_decimals, ' '); + } // Use SI-style thin space separators as these are locale independent and can't be // confused with the decimal marker. diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index a2f46c339b..56813b2d19 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -19,6 +19,7 @@ #include <validation.h> #include <stdint.h> +#include <functional> #include <QDebug> #include <QThread> diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 7f12cce1d9..7ac4cc040b 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 7c72858501..ca78c96d70 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -42,7 +42,7 @@ bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { } CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _model, const PlatformStyle *_platformStyle, QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::CoinControlDialog), m_coin_control(coin_control), model(_model), @@ -455,7 +455,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel * else if(ExtractDestination(out.txout.scriptPubKey, address)) { CPubKey pubkey; - PKHash *pkhash = boost::get<PKHash>(&address); + PKHash* pkhash = std::get_if<PKHash>(&address); if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, ToKeyID(*pkhash), pubkey)) { nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 3de7fd6d54..6ceb3de61d 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp index 5056e487fc..1467801522 100644 --- a/src/qt/createwalletdialog.cpp +++ b/src/qt/createwalletdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,10 +9,12 @@ #include <qt/createwalletdialog.h> #include <qt/forms/ui_createwalletdialog.h> +#include <qt/guiutil.h> + #include <QPushButton> CreateWalletDialog::CreateWalletDialog(QWidget* parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::CreateWalletDialog) { ui->setupUi(this); @@ -34,6 +36,32 @@ CreateWalletDialog::CreateWalletDialog(QWidget* parent) : ui->disable_privkeys_checkbox->setChecked(false); } }); + + connect(ui->disable_privkeys_checkbox, &QCheckBox::toggled, [this](bool checked) { + // Disable the encrypt_wallet_checkbox when isDisablePrivateKeysChecked is + // set to true, enable it when isDisablePrivateKeysChecked is false. + ui->encrypt_wallet_checkbox->setEnabled(!checked); + + // Wallets without private keys start out blank + if (checked) { + ui->blank_wallet_checkbox->setChecked(true); + } + + // When the encrypt_wallet_checkbox is disabled, uncheck it. + if (!ui->encrypt_wallet_checkbox->isEnabled()) { + ui->encrypt_wallet_checkbox->setChecked(false); + } + }); + +#ifndef USE_SQLITE + ui->descriptor_checkbox->setToolTip(tr("Compiled without sqlite support (required for descriptor wallets)")); + ui->descriptor_checkbox->setEnabled(false); + ui->descriptor_checkbox->setChecked(false); +#endif +#ifndef USE_BDB + ui->descriptor_checkbox->setEnabled(false); + ui->descriptor_checkbox->setChecked(true); +#endif } CreateWalletDialog::~CreateWalletDialog() diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index e0af9a20a8..e51ed9e656 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.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. @@ -13,7 +13,7 @@ EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::EditAddressDialog), mapper(nullptr), mode(_mode), diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h index 3be63156fd..f7ad80bb2d 100644 --- a/src/qt/editaddressdialog.h +++ b/src/qt/editaddressdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui index b592140dd7..881869a46c 100644 --- a/src/qt/forms/createwalletdialog.ui +++ b/src/qt/forms/createwalletdialog.ui @@ -7,127 +7,142 @@ <x>0</x> <y>0</y> <width>364</width> - <height>213</height> + <height>249</height> </rect> </property> <property name="windowTitle"> <string>Create Wallet</string> </property> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="geometry"> - <rect> - <x>10</x> - <y>170</y> - <width>341</width> - <height>32</height> - </rect> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - <widget class="QLineEdit" name="wallet_name_line_edit"> - <property name="geometry"> - <rect> - <x>120</x> - <y>20</y> - <width>231</width> - <height>24</height> - </rect> - </property> - </widget> - <widget class="QLabel" name="label"> - <property name="geometry"> - <rect> - <x>20</x> - <y>20</y> - <width>101</width> - <height>21</height> - </rect> - </property> - <property name="text"> - <string>Wallet Name</string> - </property> - </widget> - <widget class="QCheckBox" name="encrypt_wallet_checkbox"> - <property name="geometry"> - <rect> - <x>20</x> - <y>50</y> - <width>171</width> - <height>22</height> - </rect> - </property> - <property name="toolTip"> - <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string> - </property> - <property name="text"> - <string>Encrypt Wallet</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - <widget class="QCheckBox" name="disable_privkeys_checkbox"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="geometry"> - <rect> - <x>20</x> - <y>80</y> - <width>171</width> - <height>22</height> - </rect> - </property> - <property name="toolTip"> - <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string> - </property> - <property name="text"> - <string>Disable Private Keys</string> - </property> - </widget> - <widget class="QCheckBox" name="blank_wallet_checkbox"> - <property name="geometry"> - <rect> - <x>20</x> - <y>110</y> - <width>171</width> - <height>22</height> - </rect> - </property> - <property name="toolTip"> - <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string> - </property> - <property name="text"> - <string>Make Blank Wallet</string> - </property> - </widget> - <widget class="QCheckBox" name="descriptor_checkbox"> - <property name="geometry"> - <rect> - <x>20</x> - <y>140</y> - <width>171</width> - <height>22</height> - </rect> - </property> - <property name="toolTip"> - <string>Use descriptors for scriptPubKey management</string> - </property> - <property name="text"> - <string>Descriptor Wallet</string> - </property> - </widget> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="wallet_name_label"> + <property name="text"> + <string>Wallet Name</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="wallet_name_line_edit"> + <property name="minimumSize"> + <size> + <width>262</width> + <height>0</height> + </size> + </property> + <property name="placeholderText"> + <string>Wallet</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="encrypt_wallet_checkbox"> + <property name="toolTip"> + <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string> + </property> + <property name="text"> + <string>Encrypt Wallet</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_1"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>8</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Advanced Options</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_groupbox"> + <item> + <widget class="QCheckBox" name="disable_privkeys_checkbox"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="toolTip"> + <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string> + </property> + <property name="text"> + <string>Disable Private Keys</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="blank_wallet_checkbox"> + <property name="toolTip"> + <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string> + </property> + <property name="text"> + <string>Make Blank Wallet</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="descriptor_checkbox"> + <property name="toolTip"> + <string>Use descriptors for scriptPubKey management</string> + </property> + <property name="text"> + <string>Descriptor Wallet</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> </widget> <tabstops> <tabstop>wallet_name_line_edit</tabstop> <tabstop>encrypt_wallet_checkbox</tabstop> <tabstop>disable_privkeys_checkbox</tabstop> <tabstop>blank_wallet_checkbox</tabstop> + <tabstop>descriptor_checkbox</tabstop> </tabstops> <resources/> <connections> diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index d210faec03..3831852185 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -109,39 +109,13 @@ </widget> </item> <item row="3" column="0"> - <widget class="QLabel" name="label_berkeleyDBVersion"> - <property name="text"> - <string>Using BerkeleyDB version</string> - </property> - <property name="indent"> - <number>10</number> - </property> - </widget> - </item> - <item row="3" column="1" colspan="2"> - <widget class="QLabel" name="berkeleyDBVersion"> - <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_12"> <property name="text"> <string>Datadir</string> </property> </widget> </item> - <item row="4" column="1" colspan="2"> + <item row="3" column="1" colspan="2"> <widget class="QLabel" name="dataDir"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -163,14 +137,14 @@ </property> </widget> </item> - <item row="5" column="0"> + <item row="4" column="0"> <widget class="QLabel" name="label_11"> <property name="text"> <string>Blocksdir</string> </property> </widget> </item> - <item row="5" column="1" colspan="2"> + <item row="4" column="1" colspan="2"> <widget class="QLabel" name="blocksDir"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -192,14 +166,14 @@ </property> </widget> </item> - <item row="6" column="0"> + <item row="5" column="0"> <widget class="QLabel" name="label_13"> <property name="text"> <string>Startup time</string> </property> </widget> </item> - <item row="6" column="1" colspan="2"> + <item row="5" column="1" colspan="2"> <widget class="QLabel" name="startupTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -215,7 +189,7 @@ </property> </widget> </item> - <item row="7" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="labelNetwork"> <property name="font"> <font> @@ -228,14 +202,14 @@ </property> </widget> </item> - <item row="8" column="0"> + <item row="7" column="0"> <widget class="QLabel" name="label_8"> <property name="text"> <string>Name</string> </property> </widget> </item> - <item row="8" column="1" colspan="2"> + <item row="7" column="1" colspan="2"> <widget class="QLabel" name="networkName"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -251,14 +225,14 @@ </property> </widget> </item> - <item row="9" column="0"> + <item row="8" column="0"> <widget class="QLabel" name="label_7"> <property name="text"> <string>Number of connections</string> </property> </widget> </item> - <item row="9" column="1" colspan="2"> + <item row="8" column="1" colspan="2"> <widget class="QLabel" name="numberOfConnections"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -274,7 +248,7 @@ </property> </widget> </item> - <item row="10" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_10"> <property name="font"> <font> @@ -287,14 +261,14 @@ </property> </widget> </item> - <item row="11" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Current block height</string> </property> </widget> </item> - <item row="11" column="1" colspan="2"> + <item row="10" column="1" colspan="2"> <widget class="QLabel" name="numberOfBlocks"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -310,14 +284,14 @@ </property> </widget> </item> - <item row="12" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="labelLastBlockTime"> <property name="text"> <string>Last block time</string> </property> </widget> </item> - <item row="12" column="1" colspan="2"> + <item row="11" column="1" colspan="2"> <widget class="QLabel" name="lastBlockTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -333,7 +307,7 @@ </property> </widget> </item> - <item row="13" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="labelMempoolTitle"> <property name="font"> <font> @@ -346,14 +320,14 @@ </property> </widget> </item> - <item row="14" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="labelNumberOfTransactions"> <property name="text"> <string>Current number of transactions</string> </property> </widget> </item> - <item row="14" column="1"> + <item row="13" column="1"> <widget class="QLabel" name="mempoolNumberTxs"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -369,14 +343,14 @@ </property> </widget> </item> - <item row="15" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="labelMemoryUsage"> <property name="text"> <string>Memory usage</string> </property> </widget> </item> - <item row="15" column="1"> + <item row="14" column="1"> <widget class="QLabel" name="mempoolSize"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -392,7 +366,7 @@ </property> </widget> </item> - <item row="13" column="2" rowspan="3"> + <item row="12" column="2" rowspan="3"> <layout class="QVBoxLayout" name="verticalLayoutDebugButton"> <property name="spacing"> <number>3</number> @@ -432,7 +406,7 @@ </item> </layout> </item> - <item row="16" column="0"> + <item row="15" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -1103,14 +1077,17 @@ </widget> </item> <item row="1" column="0"> - <widget class="QLabel" name="label_23"> + <widget class="QLabel" name="peerConnectionTypeLabel"> + <property name="toolTip"> + <string>The type of peer connection: %1</string> + </property> <property name="text"> - <string>Direction</string> + <string>Connection Type</string> </property> </widget> </item> <item row="1" column="1"> - <widget class="QLabel" name="peerDirection"> + <widget class="QLabel" name="peerConnectionType"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> </property> @@ -1126,13 +1103,39 @@ </widget> </item> <item row="2" column="0"> + <widget class="QLabel" name="peerNetworkLabel"> + <property name="toolTip"> + <string>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</string> + </property> + <property name="text"> + <string>Network</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="peerNetwork"> + <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_21"> <property name="text"> <string>Version</string> </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QLabel" name="peerVersion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1148,14 +1151,14 @@ </property> </widget> </item> - <item row="3" column="0"> + <item row="4" column="0"> <widget class="QLabel" name="label_28"> <property name="text"> <string>User Agent</string> </property> </widget> </item> - <item row="3" column="1"> + <item row="4" column="1"> <widget class="QLabel" name="peerSubversion"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1171,14 +1174,14 @@ </property> </widget> </item> - <item row="4" column="0"> + <item row="5" column="0"> <widget class="QLabel" name="label_4"> <property name="text"> <string>Services</string> </property> </widget> </item> - <item row="4" column="1"> + <item row="5" column="1"> <widget class="QLabel" name="peerServices"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1194,14 +1197,14 @@ </property> </widget> </item> - <item row="5" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="label_29"> <property name="text"> <string>Starting Block</string> </property> </widget> </item> - <item row="5" column="1"> + <item row="6" column="1"> <widget class="QLabel" name="peerHeight"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1217,14 +1220,14 @@ </property> </widget> </item> - <item row="6" column="0"> + <item row="7" column="0"> <widget class="QLabel" name="label_27"> <property name="text"> <string>Synced Headers</string> </property> </widget> </item> - <item row="6" column="1"> + <item row="7" column="1"> <widget class="QLabel" name="peerSyncHeight"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1240,14 +1243,14 @@ </property> </widget> </item> - <item row="7" column="0"> + <item row="8" column="0"> <widget class="QLabel" name="label_25"> <property name="text"> <string>Synced Blocks</string> </property> </widget> </item> - <item row="7" column="1"> + <item row="8" column="1"> <widget class="QLabel" name="peerCommonHeight"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1263,14 +1266,14 @@ </property> </widget> </item> - <item row="8" column="0"> + <item row="9" column="0"> <widget class="QLabel" name="label_22"> <property name="text"> <string>Connection Time</string> </property> </widget> </item> - <item row="8" column="1"> + <item row="9" column="1"> <widget class="QLabel" name="peerConnTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1286,14 +1289,14 @@ </property> </widget> </item> - <item row="9" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_15"> <property name="text"> <string>Last Send</string> </property> </widget> </item> - <item row="9" column="1"> + <item row="10" column="1"> <widget class="QLabel" name="peerLastSend"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1309,14 +1312,14 @@ </property> </widget> </item> - <item row="10" column="0"> + <item row="11" column="0"> <widget class="QLabel" name="label_19"> <property name="text"> <string>Last Receive</string> </property> </widget> </item> - <item row="10" column="1"> + <item row="11" column="1"> <widget class="QLabel" name="peerLastRecv"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1332,14 +1335,14 @@ </property> </widget> </item> - <item row="11" column="0"> + <item row="12" column="0"> <widget class="QLabel" name="label_18"> <property name="text"> <string>Sent</string> </property> </widget> </item> - <item row="11" column="1"> + <item row="12" column="1"> <widget class="QLabel" name="peerBytesSent"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1355,14 +1358,14 @@ </property> </widget> </item> - <item row="12" column="0"> + <item row="13" column="0"> <widget class="QLabel" name="label_20"> <property name="text"> <string>Received</string> </property> </widget> </item> - <item row="12" column="1"> + <item row="13" column="1"> <widget class="QLabel" name="peerBytesRecv"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1378,14 +1381,14 @@ </property> </widget> </item> - <item row="13" column="0"> + <item row="14" column="0"> <widget class="QLabel" name="label_26"> <property name="text"> <string>Ping Time</string> </property> </widget> </item> - <item row="13" column="1"> + <item row="14" column="1"> <widget class="QLabel" name="peerPingTime"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1401,7 +1404,7 @@ </property> </widget> </item> - <item row="14" column="0"> + <item row="15" column="0"> <widget class="QLabel" name="peerPingWaitLabel"> <property name="toolTip"> <string>The duration of a currently outstanding ping.</string> @@ -1411,7 +1414,7 @@ </property> </widget> </item> - <item row="14" column="1"> + <item row="15" column="1"> <widget class="QLabel" name="peerPingWait"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1427,14 +1430,14 @@ </property> </widget> </item> - <item row="15" column="0"> + <item row="16" column="0"> <widget class="QLabel" name="peerMinPingLabel"> <property name="text"> <string>Min Ping</string> </property> </widget> </item> - <item row="15" column="1"> + <item row="16" column="1"> <widget class="QLabel" name="peerMinPing"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1450,14 +1453,14 @@ </property> </widget> </item> - <item row="16" column="0"> + <item row="17" column="0"> <widget class="QLabel" name="label_timeoffset"> <property name="text"> <string>Time Offset</string> </property> </widget> </item> - <item row="16" column="1"> + <item row="17" column="1"> <widget class="QLabel" name="timeoffset"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1473,7 +1476,7 @@ </property> </widget> </item> - <item row="17" column="0"> + <item row="18" column="0"> <widget class="QLabel" name="peerMappedASLabel"> <property name="toolTip"> <string>The mapped Autonomous System used for diversifying peer selection.</string> @@ -1483,7 +1486,7 @@ </property> </widget> </item> - <item row="17" column="1"> + <item row="18" column="1"> <widget class="QLabel" name="peerMappedAS"> <property name="cursor"> <cursorShape>IBeamCursor</cursorShape> @@ -1499,7 +1502,7 @@ </property> </widget> </item> - <item row="18" column="0"> + <item row="19" column="0"> <spacer name="verticalSpacer_3"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 0016fb9739..8181cc47e2 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -55,7 +55,7 @@ <item> <widget class="QCheckBox" name="prune"> <property name="toolTip"> - <string>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.</string> + <string>Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</string> </property> <property name="text"> <string>Prune &block storage to</string> @@ -260,6 +260,16 @@ </widget> </item> <item> + <widget class="QCheckBox" name="mapPortNatpmp"> + <property name="toolTip"> + <string>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</string> + </property> + <property name="text"> + <string>Map port using NA&T-PMP</string> + </property> + </widget> + </item> + <item> <widget class="QCheckBox" name="allowIncoming"> <property name="toolTip"> <string>Accept connections from outside.</string> @@ -568,12 +578,15 @@ </attribute> <layout class="QVBoxLayout" name="verticalLayout_Window"> <item> - <widget class="QCheckBox" name="hideTrayIcon"> + <widget class="QCheckBox" name="showTrayIcon"> <property name="toolTip"> - <string>Hide the icon from the system tray.</string> + <string>Show the icon in the system tray.</string> </property> <property name="text"> - <string>&Hide tray icon</string> + <string>&Show tray icon</string> + </property> + <property name="checked"> + <bool>true</bool> </property> </widget> </item> diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 4d3f90c484..ee9d4a113c 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -504,7 +504,7 @@ </layout> </item> <item> - <widget class="QListView" name="listTransactions"> + <widget class="TransactionOverviewWidget" name="listTransactions"> <property name="styleSheet"> <string notr="true">QListView { background: transparent; }</string> </property> @@ -517,9 +517,15 @@ <property name="horizontalScrollBarPolicy"> <enum>Qt::ScrollBarAlwaysOff</enum> </property> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustToContents</enum> + </property> <property name="selectionMode"> <enum>QAbstractItemView::NoSelection</enum> </property> + <property name="uniformItemSizes"> + <bool>true</bool> + </property> </widget> </item> </layout> @@ -544,6 +550,13 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>TransactionOverviewWidget</class> + <extends>QListView</extends> + <header>qt/transactionoverviewwidget.h</header> + </customwidget> + </customwidgets> <resources/> <connections/> </ui> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index bab17562a6..376acf0963 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -40,11 +40,14 @@ #include <QFontDatabase> #include <QFontMetrics> #include <QGuiApplication> +#include <QJsonObject> #include <QKeyEvent> #include <QLineEdit> #include <QList> +#include <QLocale> #include <QMenu> #include <QMouseEvent> +#include <QPluginLoader> #include <QProgressDialog> #include <QScreen> #include <QSettings> @@ -67,7 +70,7 @@ namespace GUIUtil { QString dateTimeStr(const QDateTime &date) { - return date.date().toString(Qt::SystemLocaleShortDate) + QString(" ") + date.toString("hh:mm"); + return QLocale::system().toString(date.date(), QLocale::ShortFormat) + QString(" ") + date.toString("hh:mm"); } QString dateTimeStr(qint64 nTime) @@ -654,7 +657,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) #elif defined(Q_OS_LINUX) // Follow the Desktop Application Autostart Spec: -// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html +// https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html fs::path static GetAutostartDir() { @@ -748,6 +751,34 @@ QString boostPathToQString(const fs::path &path) return QString::fromStdString(path.string()); } +QString NetworkToQString(Network net) +{ + switch (net) { + case NET_UNROUTABLE: return QObject::tr("Unroutable"); + case NET_IPV4: return "IPv4"; + case NET_IPV6: return "IPv6"; + case NET_ONION: return "Onion"; + case NET_I2P: return "I2P"; + case NET_CJDNS: return "CJDNS"; + case NET_INTERNAL: return QObject::tr("Internal"); + case NET_MAX: assert(false); + } // no default case, so the compiler can warn about missing cases + assert(false); +} + +QString ConnectionTypeToQString(ConnectionType conn_type, bool relay_txes) +{ + switch (conn_type) { + case ConnectionType::INBOUND: return relay_txes ? QObject::tr("Inbound Full Relay") : QObject::tr("Inbound Block Relay"); + case ConnectionType::OUTBOUND_FULL_RELAY: return QObject::tr("Outbound Full Relay"); + case ConnectionType::BLOCK_RELAY: return QObject::tr("Outbound Block Relay"); + case ConnectionType::MANUAL: return QObject::tr("Outbound Manual"); + case ConnectionType::FEELER: return QObject::tr("Outbound Feeler"); + case ConnectionType::ADDR_FETCH: return QObject::tr("Outbound Address Fetch"); + } // no default case, so the compiler can warn about missing cases + assert(false); +} + QString formatDurationStr(int secs) { QStringList strList; @@ -907,6 +938,20 @@ void LogQtInfo() const std::string plugin_link{"dynamic"}; #endif LogPrintf("Qt %s (%s), plugin=%s (%s)\n", qVersion(), qt_link, QGuiApplication::platformName().toStdString(), plugin_link); + const auto static_plugins = QPluginLoader::staticPlugins(); + if (static_plugins.empty()) { + LogPrintf("No static plugins.\n"); + } else { + LogPrintf("Static plugins:\n"); + for (const QStaticPlugin& p : static_plugins) { + QJsonObject meta_data = p.metaData(); + const std::string plugin_class = meta_data.take(QString("className")).toString().toStdString(); + const int plugin_version = meta_data.take(QString("version")).toInt(); + LogPrintf(" %s, version %d\n", plugin_class, plugin_version); + } + } + + LogPrintf("Style: %s / %s\n", QApplication::style()->objectName().toStdString(), QApplication::style()->metaObject()->className()); LogPrintf("System: %s, %s\n", QSysInfo::prettyProductName().toStdString(), QSysInfo::buildAbi().toStdString()); for (const QScreen* s : QGuiApplication::screens()) { LogPrintf("Screen: %s %dx%d, pixel ratio=%.1f\n", s->name().toStdString(), s->size().width(), s->size().height(), s->devicePixelRatio()); @@ -920,4 +965,35 @@ void PopupMenu(QMenu* menu, const QPoint& point, QAction* at_action) menu->popup(point, at_action); } +QDateTime StartOfDay(const QDate& date) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + return date.startOfDay(); +#else + return QDateTime(date); +#endif +} + +bool HasPixmap(const QLabel* label) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + return !label->pixmap(Qt::ReturnByValue).isNull(); +#else + return label->pixmap() != nullptr; +#endif +} + +QImage GetImage(const QLabel* label) +{ + if (!HasPixmap(label)) { + return QImage(); + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + return label->pixmap(Qt::ReturnByValue).toImage(); +#else + return label->pixmap()->toImage(); +#endif +} + } // namespace GUIUtil diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 2bd94b5eb3..edfb5b13a2 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -7,16 +7,18 @@ #include <amount.h> #include <fs.h> +#include <net.h> +#include <netaddress.h> #include <QEvent> #include <QHeaderView> #include <QItemDelegate> +#include <QLabel> #include <QMessageBox> #include <QObject> #include <QProgressBar> #include <QString> #include <QTableView> -#include <QLabel> class QValidatedLineEdit; class SendCoinsRecipient; @@ -43,6 +45,9 @@ QT_END_NAMESPACE */ namespace GUIUtil { + // Use this flags to prevent a "What's This" button in the title bar of the dialog on Windows. + constexpr auto dialog_flags = Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; + // Create human-readable string from date QString dateTimeStr(const QDateTime &datetime); QString dateTimeStr(qint64 nTime); @@ -218,22 +223,28 @@ namespace GUIUtil bool GetStartOnSystemStartup(); bool SetStartOnSystemStartup(bool fAutoStart); - /* Convert QString to OS specific boost path through UTF-8 */ + /** Convert QString to OS specific boost path through UTF-8 */ fs::path qstringToBoostPath(const QString &path); - /* Convert OS specific boost path to QString through UTF-8 */ + /** Convert OS specific boost path to QString through UTF-8 */ QString boostPathToQString(const fs::path &path); - /* Convert seconds into a QString with days, hours, mins, secs */ + /** Convert enum Network to QString */ + QString NetworkToQString(Network net); + + /** Convert enum ConnectionType to QString */ + QString ConnectionTypeToQString(ConnectionType conn_type, bool relay_txes); + + /** Convert seconds into a QString with days, hours, mins, secs */ QString formatDurationStr(int secs); - /* Format CNodeStats.nServices bitmask into a user-readable string */ + /** Format CNodeStats.nServices bitmask into a user-readable string */ QString formatServicesStr(quint64 mask); - /* Format a CNodeStats.m_ping_usec into a user-readable string or display N/A, if 0*/ + /** Format a CNodeStats.m_ping_usec into a user-readable string or display N/A, if 0 */ QString formatPingTime(int64_t ping_usec); - /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ + /** Format a CNodeCombinedStats.nTimeOffset into a user-readable string */ QString formatTimeOffset(int64_t nTimeOffset); QString formatNiceTimeOffset(qint64 secs); @@ -289,7 +300,7 @@ namespace GUIUtil /** * Returns the distance in pixels appropriate for drawing a subsequent character after text. * - * In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 13.0. + * In Qt 5.12 and before the QFontMetrics::width() is used and it is deprecated since Qt 5.13. * In Qt 5.11 the QFontMetrics::horizontalAdvance() was introduced. */ int TextWidth(const QFontMetrics& fm, const QString& text); @@ -303,6 +314,56 @@ namespace GUIUtil * Call QMenu::popup() only on supported QT_QPA_PLATFORM. */ void PopupMenu(QMenu* menu, const QPoint& point, QAction* at_action = nullptr); + + /** + * Returns the start-moment of the day in local time. + * + * QDateTime::QDateTime(const QDate& date) is deprecated since Qt 5.15. + * QDate::startOfDay() was introduced in Qt 5.14. + */ + QDateTime StartOfDay(const QDate& date); + + /** + * Returns true if pixmap has been set. + * + * QPixmap* QLabel::pixmap() is deprecated since Qt 5.15. + */ + bool HasPixmap(const QLabel* label); + QImage GetImage(const QLabel* label); + + /** + * Splits the string into substrings wherever separator occurs, and returns + * the list of those strings. Empty strings do not appear in the result. + * + * QString::split() signature differs in different Qt versions: + * - QString::SplitBehavior is deprecated since Qt 5.15 + * - Qt::SplitBehavior was introduced in Qt 5.14 + * If {QString|Qt}::SkipEmptyParts behavior is required, use this + * function instead of QString::split(). + */ + template <typename SeparatorType> + QStringList SplitSkipEmptyParts(const QString& string, const SeparatorType& separator) + { + #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + return string.split(separator, Qt::SkipEmptyParts); + #else + return string.split(separator, QString::SkipEmptyParts); + #endif + } + + /** + * Queue a function to run in an object's event loop. This can be + * replaced by a call to the QMetaObject::invokeMethod functor overload after Qt 5.10, but + * for now use a QObject::connect for compatibility with older Qt versions, based on + * https://stackoverflow.com/questions/21646467/how-to-execute-a-functor-or-a-lambda-in-a-given-thread-in-qt-gcd-style + */ + template <typename Fn> + void ObjectInvoke(QObject* object, Fn&& function, Qt::ConnectionType connection = Qt::QueuedConnection) + { + QObject source; + QObject::connect(&source, &QObject::destroyed, object, std::forward<Fn>(function), connection); + } + } // namespace GUIUtil #endif // BITCOIN_QT_GUIUTIL_H diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 235722d091..aa6b2665fa 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -119,7 +119,7 @@ int GetPruneTargetGB() } // namespace Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, int64_t chain_state_size_gb) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::Intro), thread(nullptr), signalled(false), diff --git a/src/qt/locale/bitcoin_af.ts b/src/qt/locale/bitcoin_af.ts index 23d0f609d7..908083dfb7 100644 --- a/src/qt/locale/bitcoin_af.ts +++ b/src/qt/locale/bitcoin_af.ts @@ -3,902 +3,1252 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Regs-klik om die adres of etiket te wysig</translation> + <translation>Right-click to edit address or label</translation> </message> <message> <source>Create a new address</source> - <translation>Skep 'n nuwe adres</translation> + <translation>Create a new address</translation> </message> <message> <source>&New</source> - <translation>&Nuwe</translation> + <translation>&New</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Maak 'n kopie van die huidige adres na die stelsel klipbord</translation> + <translation>Copy the currently selected address to the system clipboard</translation> </message> <message> <source>&Copy</source> - <translation>&Kopie</translation> + <translation>&Copy</translation> </message> <message> <source>C&lose</source> - <translation>S&luit</translation> + <translation>C&lose</translation> </message> <message> <source>Delete the currently selected address from the list</source> - <translation>Verwyder die uitgekiesde adres van die lys</translation> + <translation>Delete the currently selected address from the list</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>Enter address or label to search</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation>Voer inligting uit van die huidige blad na n lêer</translation> + <translation>Export the data in the current tab to a file</translation> </message> <message> <source>&Export</source> - <translation>&Uitvoer</translation> + <translation>&Export</translation> </message> <message> <source>&Delete</source> - <translation>&Verwyder</translation> + <translation>&Delete</translation> </message> <message> <source>Choose the address to send coins to</source> - <translation>Kies die address na wie die muntstukke gestuur moet word</translation> + <translation>Choose the address to send coins to</translation> </message> <message> <source>Choose the address to receive coins with</source> - <translation>Kies die adres vir die ontvangs van betaaling</translation> + <translation>Choose the address to receive coins with</translation> </message> <message> <source>C&hoose</source> - <translation>K&ies</translation> + <translation>C&hoose</translation> </message> <message> <source>Sending addresses</source> - <translation>Stuur adresse</translation> + <translation>Sending addresses</translation> </message> <message> <source>Receiving addresses</source> - <translation>Ontvang adresse</translation> + <translation>Receiving addresses</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>Dit is jou Bitcoin-adresse vir die stuur van betalings. Kontroleer altyd die bedrag en die ontvangsadres voordat u munte stuur.</translation> + <translation>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</translation> </message> <message> <source>&Copy Address</source> - <translation>&Kopie Adres</translation> + <translation>&Copy Address</translation> </message> <message> <source>Copy &Label</source> - <translation>Kopie &Etiket</translation> + <translation>Copy &Label</translation> </message> <message> <source>&Edit</source> - <translation>&Wysig</translation> + <translation>&Edit</translation> </message> <message> <source>Export Address List</source> - <translation>Voer adres lys uit</translation> + <translation>Export Address List</translation> </message> <message> <source>Comma separated file (*.csv)</source> - <translation>Koma geskeide lêer (*.csv)</translation> + <translation>Comma separated file (*.csv)</translation> </message> <message> <source>Exporting Failed</source> - <translation>Uitvoering Misluk</translation> + <translation>Exporting Failed</translation> </message> <message> <source>There was an error trying to save the address list to %1. Please try again.</source> - <translation>Kon nie die adreslys stoor na %1 nie. Probeer asseblief weer.</translation> + <translation>There was an error trying to save the address list to %1. Please try again.</translation> </message> </context> <context> <name>AddressTableModel</name> <message> <source>Label</source> - <translation>Etiket</translation> + <translation>Label</translation> </message> <message> <source>Address</source> - <translation>Adres</translation> + <translation>Address</translation> </message> <message> <source>(no label)</source> - <translation>(geen etiket)</translation> + <translation>(no label)</translation> </message> </context> <context> <name>AskPassphraseDialog</name> <message> <source>Passphrase Dialog</source> - <translation>Wagfrase Dialoog</translation> + <translation>Passphrase Dialog</translation> </message> <message> <source>Enter passphrase</source> - <translation>Tik wagfrase in</translation> + <translation>Enter passphrase</translation> </message> <message> <source>New passphrase</source> - <translation>Nuwe wagfrase</translation> + <translation>New passphrase</translation> </message> <message> <source>Repeat new passphrase</source> - <translation>Herhaal nuwe wagfrase</translation> + <translation>Repeat new passphrase</translation> + </message> + <message> + <source>Show passphrase</source> + <translation>Show passphrase</translation> </message> <message> <source>Encrypt wallet</source> - <translation>Enkripteer beursie</translation> + <translation>Encrypt wallet</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation>Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit.</translation> + <translation>This operation needs your wallet passphrase to unlock the wallet.</translation> </message> <message> <source>Unlock wallet</source> - <translation>Ontsluit beursie</translation> + <translation>Unlock wallet</translation> </message> <message> <source>This operation needs your wallet passphrase to decrypt the wallet.</source> - <translation>Hierdie operasie benodig 'n wagwoord om die beursie oop te sluit.</translation> + <translation>This operation needs your wallet passphrase to decrypt the wallet.</translation> </message> <message> <source>Decrypt wallet</source> - <translation>Dekripteer beursie</translation> + <translation>Decrypt wallet</translation> </message> <message> <source>Change passphrase</source> - <translation>Verander wagfrase</translation> + <translation>Change passphrase</translation> </message> <message> <source>Confirm wallet encryption</source> - <translation>Bevestig beursie enkripsie.</translation> + <translation>Confirm wallet encryption</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>Waarskuwing: As jy jou beursie enkripteer en jou wagwoord verloor, sal jy <b>AL JOU BITCOINS VERLOOR</b>!</translation> + <translation>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> - <translation>Is jy seker jy wil jou beursie enkripteer?</translation> + <translation>Are you sure you wish to encrypt your wallet?</translation> </message> <message> <source>Wallet encrypted</source> - <translation>Beursie enkriptasie voltooi</translation> + <translation>Wallet encrypted</translation> + </message> + <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Enter the old passphrase and new passphrase for the wallet.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Wallet to be encrypted</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Your wallet is about to be encrypted. </translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Your wallet is now encrypted. </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>BELANGRIK: Enige vorige rugsteune wat u gemaak het van u beursie-lêer moet vervang word met die nuut-gegenereerde, versleutelde beursie-lêer. Vir sekuriteitsredes sal vorige rugsteune van die onversleutelde beursie-lêer onbruikbaar word sodra u die nuwe, versleutelde beursie begin gebruik.</translation> + <translation>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.</translation> </message> <message> <source>Wallet encryption failed</source> - <translation>Beursie enkriptasie het misluk</translation> + <translation>Wallet encryption failed</translation> </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation>Beursie bewaaking het misluk as gevolg van 'n interne fout. Die beursie is nie bewaak nie!</translation> + <translation>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</translation> </message> <message> <source>The supplied passphrases do not match.</source> - <translation>Die wagfrase stem nie ooreen nie</translation> + <translation>The supplied passphrases do not match.</translation> </message> <message> <source>Wallet unlock failed</source> - <translation>Beursie oopsluiting het misluk</translation> + <translation>Wallet unlock failed</translation> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation>Die wagfrase wat ingetik was om die beursie oop te sluit, was verkeerd.</translation> + <translation>The passphrase entered for the wallet decryption was incorrect.</translation> </message> <message> <source>Wallet decryption failed</source> - <translation>Beursie dekripsie het misluk</translation> + <translation>Wallet decryption failed</translation> </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation>Die beursie se wagfrase verandering was suksesvol.</translation> + <translation>Wallet passphrase was successfully changed.</translation> </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation>Waarskuwing: Die Caps Lock is aan!</translation> + <translation>Warning: The Caps Lock key is on!</translation> </message> </context> <context> <name>BanTableModel</name> <message> <source>IP/Netmask</source> - <translation>IP/Netmasker</translation> + <translation>IP/Netmask</translation> </message> <message> <source>Banned Until</source> - <translation>Verban Tot</translation> + <translation>Banned Until</translation> </message> </context> <context> <name>BitcoinGUI</name> <message> <source>Sign &message...</source> - <translation>Teken &Boodskap</translation> + <translation>Sign &message...</translation> </message> <message> <source>Synchronizing with network...</source> - <translation>Sinchroniseer met die netwerk ...</translation> + <translation>Synchronizing with network...</translation> </message> <message> <source>&Overview</source> - <translation>&Oorsig</translation> + <translation>&Overview</translation> </message> <message> <source>Show general overview of wallet</source> - <translation>Wys algemene oorsig van die beursie</translation> + <translation>Show general overview of wallet</translation> </message> <message> <source>&Transactions</source> - <translation>&Transaksies</translation> + <translation>&Transactions</translation> </message> <message> <source>Browse transaction history</source> - <translation>Besoek transaksie geskiedenis</translation> + <translation>Browse transaction history</translation> </message> <message> <source>E&xit</source> - <translation>S&luit af</translation> + <translation>E&xit</translation> </message> <message> <source>Quit application</source> - <translation>Sluit af</translation> + <translation>Quit application</translation> </message> <message> <source>&About %1</source> - <translation>&Oor %1</translation> + <translation>&About %1</translation> </message> <message> <source>Show information about %1</source> - <translation>Wys inligting oor %1</translation> + <translation>Show information about %1</translation> </message> <message> <source>About &Qt</source> - <translation>Oor &Qt</translation> + <translation>About &Qt</translation> </message> <message> <source>Show information about Qt</source> - <translation>Wys inligting oor Qt</translation> + <translation>Show information about Qt</translation> </message> <message> <source>&Options...</source> - <translation>&Opsies</translation> + <translation>&Options...</translation> </message> <message> <source>Modify configuration options for %1</source> - <translation>Verander konfigurasie opsies vir %1</translation> + <translation>Modify configuration options for %1</translation> </message> <message> <source>&Encrypt Wallet...</source> - <translation>&Enkripteer Beursie...</translation> + <translation>&Encrypt Wallet...</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>&Rugsteun Beursie...</translation> + <translation>&Backup Wallet...</translation> </message> <message> <source>&Change Passphrase...</source> - <translation>Verander wagwoord frase...</translation> + <translation>&Change Passphrase...</translation> </message> <message> <source>Open &URI...</source> - <translation>Maak &URI oop...</translation> + <translation>Open &URI...</translation> + </message> + <message> + <source>Create Wallet...</source> + <translation>Create Wallet...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Create a new wallet</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Wallet:</translation> </message> <message> <source>Click to disable network activity.</source> - <translation>Klik om netwerk aktiwiteit af te skakel.</translation> + <translation>Click to disable network activity.</translation> </message> <message> <source>Network activity disabled.</source> - <translation>Netwerk aktiwiteid afgeskakel.</translation> + <translation>Network activity disabled.</translation> </message> <message> <source>Click to enable network activity again.</source> - <translation>Klik om netwerk aktiwiteit weer aan te skakel.</translation> + <translation>Click to enable network activity again.</translation> </message> <message> <source>Syncing Headers (%1%)...</source> - <translation>Sinkroniseer tans Hoofde (%1%)...</translation> + <translation>Syncing Headers (%1%)...</translation> </message> <message> <source>Reindexing blocks on disk...</source> - <translation>Herindekseer blokke op skyf...</translation> + <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>Stuur muntstukke na 'n Bitcoin adres</translation> + <translation>Send coins to a Bitcoin address</translation> </message> <message> <source>Backup wallet to another location</source> - <translation>Rugsteun beursie na 'n ander plek</translation> + <translation>Backup wallet to another location</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation>Verander die wagwoordfrase wat vir beursie-versleuteling gebruik word</translation> + <translation>Change the passphrase used for wallet encryption</translation> </message> <message> <source>&Verify message...</source> - <translation>&Verifieer boodskap...</translation> + <translation>&Verify message...</translation> </message> <message> <source>&Send</source> - <translation>&Stuur</translation> + <translation>&Send</translation> </message> <message> <source>&Receive</source> - <translation>&Ontvang</translation> + <translation>&Receive</translation> </message> <message> <source>&Show / Hide</source> - <translation>&Wys / Versteek</translation> + <translation>&Show / Hide</translation> </message> <message> <source>Show or hide the main Window</source> - <translation>Wys of versteek die hoof Venster</translation> + <translation>Show or hide the main Window</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation>Versleutel die private sleutels wat aan u beursie behoort</translation> + <translation>Encrypt the private keys that belong to your wallet</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>Teken boodskappe met u Bitcoin adresse om te bewys dat u hul besit</translation> + <translation>Sign messages with your Bitcoin addresses to prove you own them</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>Bevestig boodskappe om te verseker dat hulle geteken was met gespesifiseerde Bitcoin adresse</translation> + <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> </message> <message> <source>&File</source> - <translation>&Lêer</translation> + <translation>&File</translation> </message> <message> <source>&Settings</source> - <translation>&Instellings</translation> + <translation>&Settings</translation> </message> <message> <source>&Help</source> - <translation>&Hulp</translation> + <translation>&Help</translation> </message> <message> <source>Tabs toolbar</source> - <translation>Blad nutsbalk</translation> + <translation>Tabs toolbar</translation> </message> <message> <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation>Versoek betalings (genereer QR kodes en bitcoin: URIs)</translation> + <translation>Request payments (generates QR codes and bitcoin: URIs)</translation> </message> <message> <source>Show the list of used sending addresses and labels</source> - <translation>Wys die lys van gebruikte stuur adresse en etikette</translation> + <translation>Show the list of used sending addresses and labels</translation> </message> <message> <source>Show the list of used receiving addresses and labels</source> - <translation>Wys die lys van gebruikte ontvangsadresse en etikette</translation> + <translation>Show the list of used receiving addresses and labels</translation> </message> <message> <source>&Command-line options</source> - <translation>&Opdrag lys opsies</translation> + <translation>&Command-line options</translation> + </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n active connection to Bitcoin network</numerusform><numerusform>%n active connections to Bitcoin network</numerusform></translation> </message> <message> <source>Indexing blocks on disk...</source> - <translation>Indekseer tans blokke op skyf...</translation> + <translation>Indexing blocks on disk...</translation> </message> <message> <source>Processing blocks on disk...</source> - <translation>Prosesseer tans blokke op skyf...</translation> + <translation>Processing blocks on disk...</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Processed %n block of transaction history.</numerusform><numerusform>Processed %n blocks of transaction history.</numerusform></translation> </message> <message> <source>%1 behind</source> - <translation>%1 agter</translation> + <translation>%1 behind</translation> </message> <message> <source>Last received block was generated %1 ago.</source> - <translation>Ontvangs van laaste blok is %1 terug.</translation> + <translation>Last received block was generated %1 ago.</translation> </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation>Opvolgende transaksies sal nog nie sigbaar wees nie.</translation> + <translation>Transactions after this will not yet be visible.</translation> </message> <message> <source>Error</source> - <translation>Fout</translation> + <translation>Error</translation> </message> <message> <source>Warning</source> - <translation>Waarskuwing</translation> + <translation>Warning</translation> </message> <message> <source>Information</source> - <translation>Informasie</translation> + <translation>Information</translation> </message> <message> <source>Up to date</source> - <translation>Op datum</translation> + <translation>Up to date</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Open node debugging and diagnostic console</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation>&Sending addresses</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Receiving addresses</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation>Open a bitcoin: URI</translation> + </message> + <message> + <source>Open Wallet</source> + <translation>Open Wallet</translation> + </message> + <message> + <source>Open a wallet</source> + <translation>Open a wallet</translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>Close Wallet...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>Close wallet</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> + <translation>Show the %1 help message to get a list with possible Bitcoin command-line options</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> + <message> + <source>No wallets available</source> + <translation>No wallets available</translation> </message> <message> <source>&Window</source> - <translation>&Venster</translation> + <translation>&Window</translation> + </message> + <message> + <source>Minimize</source> + <translation>Minimize</translation> + </message> + <message> + <source>Zoom</source> + <translation>Zoom</translation> + </message> + <message> + <source>Main Window</source> + <translation>Main Window</translation> </message> <message> <source>%1 client</source> - <translation>%1 klient</translation> + <translation>%1 client</translation> </message> <message> <source>Connecting to peers...</source> - <translation>Verbind tans aan eweknieë...</translation> + <translation>Connecting to peers...</translation> </message> <message> <source>Catching up...</source> - <translation>Besig om op te vang...</translation> + <translation>Catching up...</translation> </message> <message> <source>Error: %1</source> - <translation>Fout: %1</translation> + <translation>Error: %1</translation> + </message> + <message> + <source>Warning: %1</source> + <translation>Warning: %1</translation> </message> <message> <source>Date: %1 </source> - <translation>Datum: %1 + <translation>Date: %1 </translation> </message> <message> <source>Amount: %1 </source> - <translation>Bedrag: %1 + <translation>Amount: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>Wallet: %1 </translation> </message> <message> <source>Type: %1 </source> - <translation>Tipe: %1 + <translation>Type: %1 </translation> </message> <message> <source>Label: %1 </source> - <translation>Etiket: %1 + <translation>Label: %1 </translation> </message> <message> <source>Address: %1 </source> - <translation>Adres: %1 + <translation>Address: %1 </translation> </message> <message> <source>Sent transaction</source> - <translation>Transaksie gestuur</translation> + <translation>Sent transaction</translation> </message> <message> <source>Incoming transaction</source> - <translation>Inkomende transaksie</translation> + <translation>Incoming transaction</translation> </message> <message> <source>HD key generation is <b>enabled</b></source> - <translation>HD sleutel generasie is <b>aangesit</b></translation> + <translation>HD key generation is <b>enabled</b></translation> </message> <message> <source>HD key generation is <b>disabled</b></source> - <translation>HD sleutel generasie is <b>afgesit</b></translation> + <translation>HD key generation is <b>disabled</b></translation> </message> <message> - <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation>Beursie is <b>versleutel</b> en is tans <b>oopgesluit</b></translation> + <source>Private key <b>disabled</b></source> + <translation>Private key <b>disabled</b></translation> </message> <message> - <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> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation>Wallet is <b>encrypted</b> and currently <b>unlocked</b></translation> </message> <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> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> <source>Coin Selection</source> - <translation>Munt Keuse</translation> + <translation>Coin Selection</translation> </message> <message> <source>Quantity:</source> - <translation>Hoeveelheid:</translation> + <translation>Quantity:</translation> </message> <message> <source>Bytes:</source> - <translation>Grepe:</translation> + <translation>Bytes:</translation> </message> <message> <source>Amount:</source> - <translation>Bedrag:</translation> + <translation>Amount:</translation> </message> <message> <source>Fee:</source> - <translation>Fooi:</translation> + <translation>Fee:</translation> </message> <message> <source>Dust:</source> - <translation>Stof:</translation> + <translation>Dust:</translation> </message> <message> <source>After Fee:</source> - <translation>Na Fooi:</translation> + <translation>After Fee:</translation> </message> <message> <source>Change:</source> - <translation>Verander:</translation> + <translation>Change:</translation> </message> <message> <source>(un)select all</source> - <translation>(on)selekteer alles</translation> + <translation>(un)select all</translation> </message> <message> <source>Tree mode</source> - <translation>Boom wyse</translation> + <translation>Tree mode</translation> </message> <message> <source>List mode</source> - <translation>Lys wyse</translation> + <translation>List mode</translation> </message> <message> <source>Amount</source> - <translation>Bedrag</translation> + <translation>Amount</translation> </message> <message> <source>Received with label</source> - <translation>Ontvang met etiket</translation> + <translation>Received with label</translation> </message> <message> <source>Received with address</source> - <translation>Ontvang met adres</translation> + <translation>Received with address</translation> </message> <message> <source>Date</source> - <translation>Datum</translation> + <translation>Date</translation> </message> <message> <source>Confirmations</source> - <translation>Bevestigings</translation> + <translation>Confirmations</translation> </message> <message> <source>Confirmed</source> - <translation>Bevestig</translation> + <translation>Confirmed</translation> </message> <message> <source>Copy address</source> - <translation>Maak kopie van adres</translation> + <translation>Copy address</translation> </message> <message> <source>Copy label</source> - <translation>Kopieer etiket</translation> + <translation>Copy label</translation> </message> <message> <source>Copy amount</source> - <translation>Kopieer bedrag</translation> + <translation>Copy amount</translation> </message> <message> <source>Copy transaction ID</source> - <translation>Kopieer transaksie ID</translation> + <translation>Copy transaction ID</translation> </message> <message> <source>Lock unspent</source> - <translation>Sluit ongespandeerde</translation> + <translation>Lock unspent</translation> </message> <message> <source>Unlock unspent</source> - <translation>Onsluit ongespandeerde</translation> + <translation>Unlock unspent</translation> </message> <message> <source>Copy quantity</source> - <translation>Kopieer hoeveelheid</translation> + <translation>Copy quantity</translation> </message> <message> <source>Copy fee</source> - <translation>Kopieer fooi</translation> + <translation>Copy fee</translation> </message> <message> <source>Copy after fee</source> - <translation>Kopieer na fooi</translation> + <translation>Copy after fee</translation> </message> <message> <source>Copy bytes</source> - <translation>Kopieer grepe</translation> + <translation>Copy bytes</translation> </message> <message> <source>Copy dust</source> - <translation>Kopieer stof</translation> + <translation>Copy dust</translation> </message> <message> <source>Copy change</source> - <translation>Kopieer verandering</translation> + <translation>Copy change</translation> </message> <message> <source>(%1 locked)</source> - <translation>(%1 gesluit)</translation> + <translation>(%1 locked)</translation> </message> <message> <source>yes</source> - <translation>ja</translation> + <translation>yes</translation> </message> <message> <source>no</source> - <translation>nee</translation> + <translation>no</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> + <translation>This label turns red if any recipient receives an amount smaller than the current dust threshold.</translation> </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation>Kan wissel met +/- %1 satoshi(s) per inset.</translation> + <translation>Can vary +/- %1 satoshi(s) per input.</translation> </message> <message> <source>(no label)</source> - <translation>(geen etiket)</translation> + <translation>(no label)</translation> </message> <message> <source>change from %1 (%2)</source> - <translation>Verander vanaf %1 (%2)</translation> + <translation>change from %1 (%2)</translation> </message> <message> <source>(change)</source> - <translation>(verander)</translation> + <translation>(change)</translation> </message> </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Creating Wallet <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Create wallet failed</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Create wallet warning</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Create Wallet</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Wallet Name</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Encrypt Wallet</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Disable Private Keys</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Make Blank Wallet</translation> + </message> + <message> + <source>Create</source> + <translation>Create</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> <source>Edit Address</source> - <translation>Wysig Adres</translation> + <translation>Edit Address</translation> </message> <message> <source>&Label</source> - <translation>&Etiket</translation> + <translation>&Label</translation> </message> <message> <source>The label associated with this address list entry</source> - <translation>Die etiket geassosieer met hierdie adreslys inskrywing</translation> + <translation>The label associated with this address list entry</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> + <translation>The address associated with this address list entry. This can only be modified for sending addresses.</translation> </message> <message> <source>&Address</source> - <translation>&Adres</translation> + <translation>&Address</translation> </message> <message> <source>New sending address</source> - <translation>Nuwe stuurende adres</translation> + <translation>New sending address</translation> </message> <message> <source>Edit receiving address</source> - <translation>Wysig ontvangende adres</translation> + <translation>Edit receiving address</translation> </message> <message> <source>Edit sending address</source> - <translation>Wysig stuurende adres</translation> + <translation>Edit sending address</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> + <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>Kon nie die beursie oopsluit nie.</translation> + <translation>Could not unlock wallet.</translation> </message> <message> <source>New key generation failed.</source> - <translation>Nuwe sleutel genereering het misluk.</translation> + <translation>New key generation failed.</translation> </message> </context> <context> <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation>n Nuwe data lêer sal geskep word.</translation> + <translation>A new data directory will be created.</translation> </message> <message> <source>name</source> - <translation>naam</translation> + <translation>name</translation> </message> <message> <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation>Lêer bestaan reeds. Voeg %1 indien u van plan is om n nuwe lêer hier te skep.</translation> + <translation>Directory already exists. Add %1 if you intend to create a new directory here.</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> + <translation>Path already exists, and is not a directory.</translation> </message> <message> <source>Cannot create data directory here.</source> - <translation>Kan nie data gids hier skep nie.</translation> + <translation>Cannot create data directory here.</translation> </message> </context> <context> <name>HelpMessageDialog</name> <message> <source>version</source> - <translation>weergawe</translation> + <translation>version</translation> </message> <message> <source>About %1</source> - <translation>Oor %1</translation> + <translation>About %1</translation> </message> <message> <source>Command-line options</source> - <translation>Opdrag lys opsies</translation> + <translation>Command-line options</translation> </message> </context> <context> <name>Intro</name> <message> <source>Welcome</source> - <translation>Welkom</translation> + <translation>Welcome</translation> </message> <message> <source>Welcome to %1.</source> - <translation>Welkom by %1.</translation> + <translation>Welcome to %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>As this is the first time the program is launched, you can choose where %1 will store its data.</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>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.</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</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>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.</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>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> </message> <message> <source>Use the default data directory</source> - <translation>Gebruik die standaard data gids</translation> + <translation>Use the default data directory</translation> </message> <message> <source>Use a custom data directory:</source> - <translation>Gebruik 'n persoonlike data gids:</translation> + <translation>Use a custom data directory:</translation> </message> <message> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Discard blocks after verification, except most recent %1 GB (prune)</translation> + </message> + <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>At least %1 GB of data will be stored in this directory, and it will grow over time.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Approximately %1 GB of data will be stored in this directory.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 will download and store a copy of the Bitcoin block chain.</translation> + </message> + <message> <source>The wallet will also be stored in this directory.</source> - <translation>Die beursie sal ook gestoor word in hierdie lêer.</translation> + <translation>The wallet will also be stored in this directory.</translation> </message> <message> <source>Error: Specified data directory "%1" cannot be created.</source> - <translation>Fout: Gespesifiseerde dataleêr "%1" kon nie geskep word nie.</translation> + <translation>Error: Specified data directory "%1" cannot be created.</translation> </message> <message> <source>Error</source> - <translation>Fout</translation> + <translation>Error</translation> </message> - </context> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB of free space available</numerusform><numerusform>%n GB of free space available</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(of %n GB needed)</numerusform><numerusform>(of %n GB needed)</numerusform></translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB needed for full chain)</numerusform><numerusform>(%n GB needed for full chain)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> <source>Form</source> - <translation>Vorm</translation> + <translation>Form</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>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.</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>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</translation> </message> <message> <source>Number of blocks left</source> - <translation>Aantal blokke oor</translation> + <translation>Number of blocks left</translation> </message> <message> <source>Unknown...</source> - <translation>Onbekend...</translation> + <translation>Unknown...</translation> </message> <message> <source>Last block time</source> - <translation>Laaste blok tyd</translation> + <translation>Last block time</translation> </message> <message> <source>Progress</source> - <translation>Vorderering</translation> + <translation>Progress</translation> </message> <message> <source>Progress increase per hour</source> - <translation>Vorderingstoename per uur</translation> + <translation>Progress increase per hour</translation> </message> <message> <source>calculating...</source> - <translation>besig met bereken...</translation> + <translation>calculating...</translation> </message> <message> <source>Estimated time left until synced</source> - <translation>Geskatte tyd oor totdat gesinkroniseer</translation> + <translation>Estimated time left until synced</translation> </message> <message> <source>Hide</source> - <translation>Steek weg</translation> + <translation>Hide</translation> </message> - </context> + <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Unknown. Syncing Headers (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Open bitcoin URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> </context> <context> <name>OpenWalletActivity</name> - </context> + <message> + <source>Open wallet failed</source> + <translation>Open wallet failed</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Open wallet warning</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> + <message> + <source>Opening Wallet <b>%1</b>...</source> + <translation>Opening Wallet <b>%1</b>...</translation> + </message> +</context> <context> <name>OptionsDialog</name> <message> <source>Options</source> - <translation>Opsies</translation> + <translation>Options</translation> </message> <message> <source>&Main</source> - <translation>&Hoof</translation> + <translation>&Main</translation> </message> <message> <source>Automatically start %1 after logging in to the system.</source> - <translation>Begin %1 outomaties nadat jy aangemeld is by die stelsel.</translation> + <translation>Automatically start %1 after logging in to the system.</translation> </message> <message> <source>&Start %1 on system login</source> - <translation>&Begin %1 op stelsel aanmelding</translation> + <translation>&Start %1 on system login</translation> </message> <message> <source>Size of &database cache</source> - <translation>Grootte van &databasis kas</translation> + <translation>Size of &database cache</translation> </message> <message> <source>Number of script &verification threads</source> - <translation>Aantal skrip &verifikasie drade</translation> + <translation>Number of script &verification threads</translation> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>IP address of the proxy (e.g. 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>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</translation> + </message> + <message> + <source>Hide the icon from the system tray.</source> + <translation>Hide the icon from the system tray.</translation> + </message> + <message> + <source>&Hide tray icon</source> + <translation>&Hide tray icon</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>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.</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>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 |.</translation> </message> <message> <source>Open the %1 configuration file from the working directory.</source> - <translation>Maak die %1 konfigurasie lêer oop van die werk gids.</translation> + <translation>Open the %1 configuration file from the working directory.</translation> </message> <message> <source>Open Configuration File</source> - <translation>Open Konfigurasie Lêer</translation> + <translation>Open Configuration File</translation> </message> <message> <source>Reset all client options to default.</source> - <translation>Alle kliëntopsies na verstek terugstel.</translation> + <translation>Reset all client options to default.</translation> </message> <message> <source>&Reset Options</source> - <translation>&Herstel Opsies</translation> + <translation>&Reset Options</translation> </message> <message> <source>&Network</source> - <translation>&Netwerk</translation> + <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>MiB</source> + <translation>MiB</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = auto, <0 = leave that many cores free)</translation> </message> <message> <source>W&allet</source> - <translation>&Beursie</translation> + <translation>W&allet</translation> </message> <message> <source>Expert</source> - <translation>Kenner</translation> + <translation>Expert</translation> </message> <message> <source>Enable coin &control features</source> - <translation>Bemagtig munt &beheer funksies.</translation> + <translation>Enable coin &control features</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>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.</translation> </message> <message> <source>&Spend unconfirmed change</source> - <translation>&Spandeer onbevestigde kleingeld</translation> + <translation>&Spend unconfirmed change</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>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <translation>Map port using &UPnP</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation>Accept connections from outside.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Allow incomin&g connections</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation>Connect to the Bitcoin network through a SOCKS5 proxy.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Connect through SOCKS5 proxy (default 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 of the proxy (e.g. 9050)</translation> + </message> + <message> <source>Used for reaching peers via:</source> - <translation>Word gebruik vir die bereik van eweknieë via:</translation> + <translation>Used for reaching peers via:</translation> </message> <message> <source>IPv4</source> @@ -914,27 +1264,51 @@ </message> <message> <source>&Window</source> - <translation>&Venster</translation> + <translation>&Window</translation> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation>Show only a tray icon after minimizing the window.</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation>&Minimize to the tray instead of the taskbar</translation> </message> <message> <source>M&inimize on close</source> - <translation>V&erminder op toemaak</translation> + <translation>M&inimize on close</translation> </message> <message> <source>&Display</source> - <translation>&Vertoon</translation> + <translation>&Display</translation> </message> <message> <source>User Interface &language:</source> - <translation>Gebruikers Koppelvlak &taal:</translation> + <translation>User Interface &language:</translation> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>The user interface language can be set here. This setting will take effect after restarting %1.</translation> </message> <message> <source>&Unit to show amounts in:</source> - <translation>&Eenheid om bedrae te toon in:</translation> + <translation>&Unit to show amounts in:</translation> + </message> + <message> + <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> + <translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation> </message> <message> <source>Whether to show coin control features or not.</source> - <translation>Of om munt beheer funksies te wys of nie.</translation> + <translation>Whether to show coin control features or not.</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>&Third party transaction URLs</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Options set in this dialog are overridden by the command line or in the configuration file:</translation> </message> <message> <source>&OK</source> @@ -942,135 +1316,218 @@ </message> <message> <source>&Cancel</source> - <translation>&Kanselleer</translation> + <translation>&Cancel</translation> </message> <message> <source>default</source> - <translation>standaard</translation> + <translation>default</translation> </message> <message> <source>none</source> - <translation>niks</translation> + <translation>none</translation> </message> <message> <source>Confirm options reset</source> - <translation>Bevestig terugstel van opsies</translation> + <translation>Confirm options reset</translation> </message> <message> <source>Client restart required to activate changes.</source> - <translation>Kliënt moet herbegin word om veranderinge te aktiveer.</translation> + <translation>Client restart required to activate changes.</translation> </message> <message> <source>Client will be shut down. Do you want to proceed?</source> - <translation>Kliënt sal toegemaak word. Wil u voortgaan?</translation> + <translation>Client will be shut down. Do you want to proceed?</translation> </message> <message> <source>Configuration options</source> - <translation>Konfigurasie opsies</translation> + <translation>Configuration options</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>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</translation> </message> <message> <source>Error</source> - <translation>Fout</translation> + <translation>Error</translation> </message> <message> <source>The configuration file could not be opened.</source> - <translation>Die konfigurasie lêer kon nie oopgemaak word nie.</translation> + <translation>The configuration file could not be opened.</translation> </message> <message> <source>This change would require a client restart.</source> - <translation>Hierdie verandering sal 'n herbegin van die kliënt vereis. </translation> + <translation>This change would require a client restart.</translation> </message> <message> <source>The supplied proxy address is invalid.</source> - <translation>Die verskafde volmag adres is ongeldig.</translation> + <translation>The supplied proxy address is invalid.</translation> </message> </context> <context> <name>OverviewPage</name> <message> <source>Form</source> - <translation>Vorm</translation> + <translation>Form</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>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.</translation> </message> <message> <source>Watch-only:</source> - <translation>Kyk-net:</translation> + <translation>Watch-only:</translation> </message> <message> <source>Available:</source> - <translation>Beskikbaar:</translation> + <translation>Available:</translation> </message> <message> <source>Your current spendable balance</source> - <translation>U huidige bruikbare balans</translation> + <translation>Your current spendable balance</translation> </message> <message> <source>Pending:</source> - <translation>Hangend:</translation> + <translation>Pending:</translation> + </message> + <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> </message> <message> <source>Immature:</source> - <translation>Onvolwasse:</translation> + <translation>Immature:</translation> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation>Mined balance that has not yet matured</translation> </message> <message> <source>Balances</source> - <translation>Balans</translation> + <translation>Balances</translation> </message> <message> <source>Total:</source> - <translation>Totaal:</translation> + <translation>Total:</translation> </message> <message> <source>Your current total balance</source> - <translation>U huidige totale balans</translation> + <translation>Your current total balance</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>Your current balance in watch-only addresses</translation> </message> <message> <source>Spendable:</source> - <translation>Besteebaar:</translation> + <translation>Spendable:</translation> </message> <message> <source>Recent transactions</source> - <translation>Onlangse transaksies</translation> + <translation>Recent transactions</translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Unconfirmed transactions to watch-only addresses</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Mined balance in watch-only addresses that has not yet matured</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Current total balance in watch-only addresses</translation> + </message> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> </message> </context> <context> <name>PaymentServer</name> <message> <source>Payment request error</source> - <translation>Betalings versoek fout</translation> + <translation>Payment request error</translation> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Cannot start bitcoin: click-to-pay handler</translation> </message> <message> <source>URI handling</source> - <translation>URI hantering</translation> + <translation>URI handling</translation> </message> - </context> + <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>Cannot process payment request because BIP70 is not supported.</source> + <translation>Cannot process payment request because BIP70 is not supported.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</translation> + </message> + <message> + <source>Invalid payment address %1</source> + <translation>Invalid payment address %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 cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Payment request file handling</translation> + </message> +</context> <context> <name>PeerTableModel</name> <message> <source>User Agent</source> - <translation>Gebruikeragent</translation> + <translation>User Agent</translation> + </message> + <message> + <source>Node/Service</source> + <translation>Node/Service</translation> </message> <message> <source>NodeId</source> - <translation>NodusId</translation> + <translation>NodeId</translation> + </message> + <message> + <source>Ping</source> + <translation>Ping</translation> </message> <message> <source>Sent</source> - <translation>Gestuur</translation> + <translation>Sent</translation> </message> <message> <source>Received</source> - <translation>Ontvang</translation> + <translation>Received</translation> </message> </context> <context> <name>QObject</name> <message> <source>Amount</source> - <translation>Bedrag</translation> + <translation>Amount</translation> </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> - <translation>Voer in 'n Bitcoin adres (bv. %1)</translation> + <translation>Enter a Bitcoin address (e.g. %1)</translation> </message> <message> <source>%1 d</source> @@ -1090,19 +1547,43 @@ </message> <message> <source>None</source> - <translation>Geen</translation> + <translation>None</translation> </message> <message> <source>N/A</source> - <translation>n.v.t.</translation> + <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 second</numerusform><numerusform>%n seconds</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>%n minute</numerusform><numerusform>%n minutes</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n hour</numerusform><numerusform>%n hours</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n day</numerusform><numerusform>%n days</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n week</numerusform><numerusform>%n weeks</numerusform></translation> + </message> <message> <source>%1 and %2</source> - <translation>%1 en %2</translation> + <translation>%1 and %2</translation> + </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation><numerusform>%n year</numerusform><numerusform>%n years</numerusform></translation> </message> <message> <source>%1 B</source> @@ -1121,98 +1602,262 @@ <translation>%1 GB</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>Fout: %1</translation> + <translation>Error: %1</translation> + </message> + <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 didn't yet exit safely...</translation> </message> <message> <source>unknown</source> - <translation>onbekend</translation> + <translation>unknown</translation> </message> </context> <context> <name>QRImageWidget</name> <message> <source>&Save Image...</source> - <translation>&Stoor beeld</translation> + <translation>&Save Image...</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&Copy Image</translation> </message> <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> + <translation>Resulting URI too long, try to reduce the text for label / message.</translation> </message> <message> <source>Error encoding URI into QR Code.</source> - <translation>Fout met enkodering van URI na QR kode</translation> + <translation>Error encoding URI into QR Code.</translation> </message> - </context> + <message> + <source>QR code support not available.</source> + <translation>QR code support not available.</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>Save QR Code</translation> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>PNG Image (*.png)</translation> + </message> +</context> <context> <name>RPCConsole</name> <message> <source>N/A</source> - <translation>n.v.t.</translation> + <translation>N/A</translation> </message> <message> <source>Client version</source> - <translation>Kliëntweergawe</translation> + <translation>Client version</translation> </message> <message> <source>&Information</source> - <translation>Informasie</translation> + <translation>&Information</translation> </message> <message> <source>General</source> - <translation>Algemeen</translation> + <translation>General</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Using BerkeleyDB version</translation> + </message> + <message> + <source>Datadir</source> + <translation>Datadir</translation> + </message> + <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>To specify a non-default location of the data directory use the '%1' option.</translation> + </message> + <message> + <source>Blocksdir</source> + <translation>Blocksdir</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>To specify a non-default location of the blocks directory use the '%1' option.</translation> + </message> + <message> + <source>Startup time</source> + <translation>Startup time</translation> </message> <message> <source>Network</source> - <translation>Netwerk</translation> + <translation>Network</translation> </message> <message> <source>Name</source> - <translation>Naam</translation> + <translation>Name</translation> </message> <message> <source>Number of connections</source> - <translation>Aantal verbindings</translation> + <translation>Number of connections</translation> </message> <message> <source>Block chain</source> - <translation>Blokketting</translation> + <translation>Block chain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Huidige aantal blokke</translation> + <source>Memory Pool</source> + <translation>Memory Pool</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation>Current number of transactions</translation> + </message> + <message> + <source>Memory usage</source> + <translation>Memory usage</translation> + </message> + <message> + <source>Wallet: </source> + <translation>Wallet: </translation> + </message> + <message> + <source>(none)</source> + <translation>(none)</translation> + </message> + <message> + <source>&Reset</source> + <translation>&Reset</translation> </message> <message> <source>Received</source> - <translation>Ontvang</translation> + <translation>Received</translation> </message> <message> <source>Sent</source> - <translation>Gestuur</translation> + <translation>Sent</translation> + </message> + <message> + <source>&Peers</source> + <translation>&Peers</translation> </message> <message> <source>Banned peers</source> - <translation>Verbanne porture</translation> + <translation>Banned peers</translation> </message> <message> - <source>Whitelisted</source> - <translation>Gewitlys</translation> + <source>Select a peer to view detailed information.</source> + <translation>Select a peer to view detailed information.</translation> </message> <message> <source>Direction</source> - <translation>Rigting</translation> + <translation>Direction</translation> </message> <message> <source>Version</source> - <translation>Weergawe</translation> + <translation>Version</translation> + </message> + <message> + <source>Starting Block</source> + <translation>Starting Block</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Synced Headers</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Synced Blocks</translation> + </message> + <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>The mapped Autonomous System used for diversifying peer selection.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapped AS</translation> </message> <message> <source>User Agent</source> - <translation>Gebruikeragent</translation> + <translation>User Agent</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</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>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>Decrease font size</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Increase font size</translation> + </message> + <message> + <source>Services</source> + <translation>Services</translation> + </message> + <message> + <source>Connection Time</source> + <translation>Connection Time</translation> + </message> + <message> + <source>Last Send</source> + <translation>Last Send</translation> + </message> + <message> + <source>Last Receive</source> + <translation>Last Receive</translation> + </message> + <message> + <source>Ping Time</source> + <translation>Ping Time</translation> + </message> + <message> + <source>The duration of a currently outstanding ping.</source> + <translation>The duration of a currently outstanding ping.</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>Ping Wait</translation> + </message> + <message> + <source>Min Ping</source> + <translation>Min Ping</translation> + </message> + <message> + <source>Time Offset</source> + <translation>Time Offset</translation> </message> <message> <source>Last block time</source> - <translation>Laaste blok tyd</translation> + <translation>Last block time</translation> + </message> + <message> + <source>&Open</source> + <translation>&Open</translation> + </message> + <message> + <source>&Console</source> + <translation>&Console</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation>&Network Traffic</translation> + </message> + <message> + <source>Totals</source> + <translation>Totals</translation> </message> <message> <source>In:</source> @@ -1220,15 +1865,23 @@ </message> <message> <source>Out:</source> - <translation>Uit:</translation> + <translation>Out:</translation> + </message> + <message> + <source>Debug log file</source> + <translation>Debug log file</translation> + </message> + <message> + <source>Clear console</source> + <translation>Clear console</translation> </message> <message> <source>1 &hour</source> - <translation>1 &uur</translation> + <translation>1 &hour</translation> </message> <message> <source>1 &day</source> - <translation>1 &dag</translation> + <translation>1 &day</translation> </message> <message> <source>1 &week</source> @@ -1236,27 +1889,55 @@ </message> <message> <source>1 &year</source> - <translation>1 &jaar</translation> + <translation>1 &year</translation> </message> <message> <source>&Disconnect</source> - <translation>&Ontkoppel</translation> + <translation>&Disconnect</translation> </message> <message> <source>Ban for</source> - <translation>Verbied vir</translation> + <translation>Ban for</translation> </message> <message> <source>&Unban</source> - <translation>&Toegelaat</translation> + <translation>&Unban</translation> + </message> + <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Welcome to the %1 RPC console.</translation> + </message> + <message> + <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> + <translation>Use up and down arrows to navigate history, and %1 to clear screen.</translation> + </message> + <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Type %1 for an overview of available commands.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>For more information on using this console type %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>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.</translation> </message> <message> <source>Network activity disabled</source> - <translation>Netwerk aktiewiteit gedeaktiveer</translation> + <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>(nodus id: %1)</translation> + <translation>(node id: %1)</translation> </message> <message> <source>via %1</source> @@ -1264,412 +1945,522 @@ </message> <message> <source>never</source> - <translation>nooit</translation> + <translation>never</translation> </message> <message> <source>Inbound</source> - <translation>Inkomende</translation> + <translation>Inbound</translation> </message> <message> <source>Outbound</source> - <translation>Uitgaande</translation> - </message> - <message> - <source>Yes</source> - <translation>Ja</translation> - </message> - <message> - <source>No</source> - <translation>Nee</translation> + <translation>Outbound</translation> </message> <message> <source>Unknown</source> - <translation>Onbekend</translation> + <translation>Unknown</translation> </message> </context> <context> <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation>&Bedrag:</translation> + <translation>&Amount:</translation> </message> <message> <source>&Label:</source> - <translation>&Etiket:</translation> + <translation>&Label:</translation> </message> <message> <source>&Message:</source> - <translation>&Boodskap:</translation> + <translation>&Message:</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>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.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <translation>An optional label to associate with the new receiving address.</translation> + </message> + <message> + <source>Use this form to request payments. All fields are <b>optional</b>.</source> + <translation>Use this form to request payments. All fields are <b>optional</b>.</translation> + </message> + <message> + <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <translation>An optional amount to request. Leave this empty or zero to not request a specific amount.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>An optional message that is attached to the payment request and may be displayed to the sender.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Create new receiving address</translation> </message> <message> <source>Clear all fields of the form.</source> - <translation>Vee alle velde op die vorm skoon</translation> + <translation>Clear all fields of the form.</translation> </message> <message> <source>Clear</source> - <translation>Skoonmaak</translation> + <translation>Clear</translation> </message> <message> - <source>Show</source> - <translation>Wys</translation> + <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>Remove</source> - <translation>Verwyder</translation> + <source>Generate native segwit (Bech32) address</source> + <translation>Generate native segwit (Bech32) address</translation> </message> <message> - <source>Copy label</source> - <translation>Kopieer etiket</translation> + <source>Requested payments history</source> + <translation>Requested payments history</translation> </message> <message> - <source>Copy message</source> - <translation>Kopieer boodskap</translation> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation>Show the selected request (does the same as double clicking an entry)</translation> </message> <message> - <source>Copy amount</source> - <translation>Kopieer bedrag</translation> + <source>Show</source> + <translation>Show</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Kode</translation> + <source>Remove the selected entries from the list</source> + <translation>Remove the selected entries from the list</translation> </message> <message> - <source>Copy &URI</source> - <translation>Kopieer &URI</translation> + <source>Remove</source> + <translation>Remove</translation> </message> <message> - <source>Copy &Address</source> - <translation>Kopieer &Address</translation> + <source>Copy URI</source> + <translation>Copy URI</translation> </message> <message> - <source>&Save Image...</source> - <translation>&Stoor beeld</translation> + <source>Copy label</source> + <translation>Copy label</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Versoek betaling van %1</translation> + <source>Copy message</source> + <translation>Copy message</translation> </message> <message> - <source>Payment information</source> - <translation>Betaling informasie</translation> + <source>Copy amount</source> + <translation>Copy amount</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Could not unlock wallet.</source> + <translation>Could not unlock wallet.</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>Adres</translation> + <source>Amount:</source> + <translation>Amount:</translation> </message> <message> - <source>Amount</source> - <translation>Bedrag</translation> + <source>Message:</source> + <translation>Message:</translation> </message> <message> - <source>Label</source> - <translation>Etiket</translation> + <source>Wallet:</source> + <translation>Wallet:</translation> </message> <message> - <source>Message</source> - <translation>Boodskap</translation> + <source>Copy &URI</source> + <translation>Copy &URI</translation> + </message> + <message> + <source>Copy &Address</source> + <translation>Copy &Address</translation> + </message> + <message> + <source>&Save Image...</source> + <translation>&Save Image...</translation> + </message> + <message> + <source>Request payment to %1</source> + <translation>Request payment to %1</translation> </message> <message> - <source>Wallet</source> - <translation>Beursie</translation> + <source>Payment information</source> + <translation>Payment information</translation> </message> </context> <context> <name>RecentRequestsTableModel</name> <message> <source>Date</source> - <translation>Datum</translation> + <translation>Date</translation> </message> <message> <source>Label</source> - <translation>Etiket</translation> + <translation>Label</translation> </message> <message> <source>Message</source> - <translation>Boodskap</translation> + <translation>Message</translation> </message> <message> <source>(no label)</source> - <translation>(geen etiket)</translation> + <translation>(no label)</translation> </message> <message> <source>(no message)</source> - <translation>(geen boodskap)</translation> + <translation>(no message)</translation> </message> <message> <source>(no amount requested)</source> - <translation>(geen bedrag versoek)</translation> + <translation>(no amount requested)</translation> </message> <message> <source>Requested</source> - <translation>Versoekte</translation> + <translation>Requested</translation> </message> </context> <context> <name>SendCoinsDialog</name> <message> <source>Send Coins</source> - <translation>Stuur Munstukke</translation> + <translation>Send Coins</translation> </message> <message> <source>Coin Control Features</source> - <translation>Munt Beheer Kenmerke</translation> + <translation>Coin Control Features</translation> </message> <message> <source>Inputs...</source> - <translation>Insette...</translation> + <translation>Inputs...</translation> </message> <message> <source>automatically selected</source> - <translation>outomaties gekies</translation> + <translation>automatically selected</translation> </message> <message> <source>Insufficient funds!</source> - <translation>Onvoldoende fondse</translation> + <translation>Insufficient funds!</translation> </message> <message> <source>Quantity:</source> - <translation>Hoeveelheid:</translation> + <translation>Quantity:</translation> </message> <message> <source>Bytes:</source> - <translation>Grepe:</translation> + <translation>Bytes:</translation> </message> <message> <source>Amount:</source> - <translation>Bedrag:</translation> + <translation>Amount:</translation> </message> <message> <source>Fee:</source> - <translation>Fooi:</translation> + <translation>Fee:</translation> </message> <message> <source>After Fee:</source> - <translation>Na Fooi:</translation> + <translation>After Fee:</translation> </message> <message> <source>Change:</source> - <translation>Verander:</translation> + <translation>Change:</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>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</translation> + </message> + <message> + <source>Custom change address</source> + <translation>Custom change address</translation> </message> <message> <source>Transaction Fee:</source> - <translation>Transaksie fooi:</translation> + <translation>Transaction Fee:</translation> </message> <message> <source>Choose...</source> - <translation>Kies...</translation> + <translation>Choose...</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> + <translation>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.</translation> </message> <message> <source>Warning: Fee estimation is currently not possible.</source> - <translation>Waarskuwing: fooiskatting is tans onbeskikbaar</translation> + <translation>Warning: Fee estimation is currently not possible.</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 kilogreep</translation> + <translation>per kilobyte</translation> </message> <message> <source>Hide</source> - <translation>Steek weg</translation> + <translation>Hide</translation> </message> <message> <source>Recommended:</source> - <translation>Aanbeveel:</translation> + <translation>Recommended:</translation> </message> <message> <source>Custom:</source> - <translation>Aangepaste:</translation> + <translation>Custom:</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> + <translation>(Smart fee not initialized yet. This usually takes a few blocks...)</translation> </message> <message> <source>Send to multiple recipients at once</source> - <translation>Stuur aan vele ontvangers op eens</translation> + <translation>Send to multiple recipients at once</translation> </message> <message> <source>Add &Recipient</source> - <translation>Voeg by &Ontvanger</translation> + <translation>Add &Recipient</translation> </message> <message> <source>Clear all fields of the form.</source> - <translation>Vee alle velde op die vorm skoon</translation> + <translation>Clear all fields of the form.</translation> </message> <message> <source>Dust:</source> - <translation>Stof:</translation> + <translation>Dust:</translation> + </message> + <message> + <source>Hide transaction fee settings</source> + <translation>Hide transaction fee settings</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>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.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>A too low fee might result in a never confirming transaction (read the tooltip)</translation> </message> <message> <source>Confirmation time target:</source> - <translation>Bevestigingstyd teiken:</translation> + <translation>Confirmation time target:</translation> </message> <message> <source>Enable Replace-By-Fee</source> - <translation>Bemoontlik vervang-deur-fooi</translation> + <translation>Enable 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>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> + <translation>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.</translation> </message> <message> <source>Clear &All</source> - <translation>Vee &Alles skoon</translation> + <translation>Clear &All</translation> </message> <message> <source>Balance:</source> - <translation>Balans:</translation> + <translation>Balance:</translation> </message> <message> <source>Confirm the send action</source> - <translation>Bevestig stuuraksie</translation> + <translation>Confirm the send action</translation> </message> <message> <source>S&end</source> - <translation>S&tuur</translation> + <translation>S&end</translation> </message> <message> <source>Copy quantity</source> - <translation>Kopieer hoeveelheid</translation> + <translation>Copy quantity</translation> </message> <message> <source>Copy amount</source> - <translation>Kopieer bedrag</translation> + <translation>Copy amount</translation> </message> <message> <source>Copy fee</source> - <translation>Kopieer fooi</translation> + <translation>Copy fee</translation> </message> <message> <source>Copy after fee</source> - <translation>Kopieer na fooi</translation> + <translation>Copy after fee</translation> </message> <message> <source>Copy bytes</source> - <translation>Kopieer grepe</translation> + <translation>Copy bytes</translation> </message> <message> <source>Copy dust</source> - <translation>Kopieer stof</translation> + <translation>Copy dust</translation> </message> <message> <source>Copy change</source> - <translation>Kopieer verandering</translation> + <translation>Copy change</translation> </message> <message> <source>%1 (%2 blocks)</source> - <translation>%1 (%2 blokke)</translation> + <translation>%1 (%2 blocks)</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation>Cr&eate Unsigned</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation> from wallet '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 to '%2'</translation> </message> <message> <source>%1 to %2</source> - <translation>%1 tot %2</translation> + <translation>%1 to %2</translation> + </message> + <message> + <source>Do you want to draft this transaction?</source> + <translation>Do you want to draft this transaction?</translation> </message> <message> <source>Are you sure you want to send?</source> - <translation>Is u seker u wil verstuur?</translation> + <translation>Are you sure you want to send?</translation> </message> <message> <source>or</source> - <translation>of</translation> + <translation>or</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> + <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Please, review your transaction.</translation> </message> <message> <source>Transaction fee</source> - <translation>Transaksie fooi</translation> + <translation>Transaction fee</translation> </message> <message> <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation>Sein nie Vervang-Met-Fooi nie, BIP-25</translation> + <translation>Not signalling Replace-By-Fee, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>To review recipient list click "Show Details..."</source> + <translation>To review recipient list click "Show Details..."</translation> </message> <message> <source>Confirm send coins</source> - <translation>Bevestig versending van munte</translation> + <translation>Confirm send coins</translation> + </message> + <message> + <source>Confirm transaction proposal</source> + <translation>Confirm transaction proposal</translation> + </message> + <message> + <source>Send</source> + <translation>Send</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Watch-only balance:</translation> </message> <message> <source>The recipient address is not valid. Please recheck.</source> - <translation>Die ontvangeradres is ongeldig. Kyk asseblief weer mooi.</translation> + <translation>The recipient address is not valid. Please recheck.</translation> </message> <message> <source>The amount to pay must be larger than 0.</source> - <translation>Bedrag moet groter as nul wees</translation> + <translation>The amount to pay must be larger than 0.</translation> </message> <message> <source>The amount exceeds your balance.</source> - <translation>Die bedrag oorskry jou saldo</translation> + <translation>The amount exceeds your balance.</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> + <translation>The total exceeds your balance when the %1 transaction fee is included.</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> + <translation>Duplicate address found: addresses should only be used once each.</translation> </message> <message> <source>Transaction creation failed!</source> - <translation>Transaksieopstelling het gefaal</translation> + <translation>Transaction creation failed!</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> + <translation>A fee higher than %1 is considered an absurdly high fee.</translation> </message> <message> <source>Payment request expired.</source> - <translation>Betalings versoek verstryk.</translation> + <translation>Payment request expired.</translation> + </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Estimated to begin confirmation within %n block.</numerusform><numerusform>Estimated to begin confirmation within %n blocks.</numerusform></translation> </message> <message> <source>Warning: Invalid Bitcoin address</source> - <translation>Waarskuwing: Ongeldige Bitcoinadres</translation> + <translation>Warning: Invalid Bitcoin address</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>Warning: Unknown change address</translation> + </message> + <message> + <source>Confirm custom change address</source> + <translation>Confirm custom change address</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> + <translation>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?</translation> </message> <message> <source>(no label)</source> - <translation>(geen etiket)</translation> + <translation>(no label)</translation> </message> </context> <context> <name>SendCoinsEntry</name> <message> <source>A&mount:</source> - <translation>&Bedrag:</translation> + <translation>A&mount:</translation> </message> <message> <source>Pay &To:</source> - <translation>Betaal &Vir:</translation> + <translation>Pay &To:</translation> </message> <message> <source>&Label:</source> - <translation>&Etiket:</translation> + <translation>&Label:</translation> </message> <message> <source>Choose previously used address</source> - <translation>Kies voorheen gebruikte adres</translation> + <translation>Choose previously used address</translation> </message> <message> <source>The Bitcoin address to send the payment to</source> - <translation>Die Bitcoinadres waarheen die betaling gestuur word</translation> + <translation>The Bitcoin address to send the payment to</translation> </message> <message> <source>Alt+A</source> @@ -1677,57 +2468,93 @@ Is u seker?</translation> </message> <message> <source>Paste address from clipboard</source> - <translation>Plak adres van aanknipbord af</translation> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> </message> <message> <source>Remove this entry</source> - <translation>Verwyder hierdie inskrywing</translation> + <translation>Remove this entry</translation> + </message> + <message> + <source>The amount to send in the selected unit</source> + <translation>The amount to send in the selected unit</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> + <translation>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.</translation> </message> <message> <source>S&ubtract fee from amount</source> - <translation>Bedrag &Sonder fooi </translation> + <translation>S&ubtract fee from amount</translation> </message> <message> <source>Use available balance</source> - <translation>Gebruik beskikbare saldo</translation> + <translation>Use available balance</translation> </message> <message> <source>Message:</source> - <translation>Boodskap:</translation> + <translation>Message:</translation> </message> <message> <source>This is an unauthenticated payment request.</source> - <translation>Hierdie is 'n ongemagtigde uitbetalingsversoek</translation> + <translation>This is an unauthenticated payment request.</translation> </message> <message> <source>This is an authenticated payment request.</source> - <translation>Hierdie is 'n gemagtigde uitbetalingsversoek -</translation> + <translation>This is an authenticated payment request.</translation> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation>Enter a label for this address to add it to the list of used addresses</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>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.</translation> </message> <message> <source>Pay To:</source> - <translation>Betaal Vir:</translation> + <translation>Pay To:</translation> </message> - </context> + <message> + <source>Memo:</source> + <translation>Memo:</translation> + </message> +</context> <context> <name>ShutdownWindow</name> - </context> + <message> + <source>%1 is shutting down...</source> + <translation>%1 is shutting down...</translation> + </message> + <message> + <source>Do not shut down the computer until this window disappears.</source> + <translation>Do not shut down the computer until this window disappears.</translation> + </message> +</context> <context> <name>SignVerifyMessageDialog</name> <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Signatures - Sign / Verify a Message</translation> + </message> + <message> <source>&Sign Message</source> - <translation>&Teken boodskap</translation> + <translation>&Sign Message</translation> + </message> + <message> + <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <translation>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.</translation> + </message> + <message> + <source>The Bitcoin address to sign the message with</source> + <translation>The Bitcoin address to sign the message with</translation> </message> <message> <source>Choose previously used address</source> - <translation>Kies voorheen gebruikte adres</translation> + <translation>Choose previously used address</translation> </message> <message> <source>Alt+A</source> @@ -1735,35 +2562,127 @@ word die fooi eweredig verdeel.</translation> </message> <message> <source>Paste address from clipboard</source> - <translation>Plak adres van aanknipbord af</translation> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Enter the message you want to sign here</source> + <translation>Enter the message you want to sign here</translation> </message> <message> <source>Signature</source> - <translation>Handtekening</translation> + <translation>Signature</translation> + </message> + <message> + <source>Copy the current signature to the system clipboard</source> + <translation>Copy the current signature to the system clipboard</translation> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation>Sign the message to prove you own this Bitcoin address</translation> </message> <message> <source>Sign &Message</source> - <translation>Teken &Boodskap</translation> + <translation>Sign &Message</translation> + </message> + <message> + <source>Reset all sign message fields</source> + <translation>Reset all sign message fields</translation> </message> <message> <source>Clear &All</source> - <translation>Vee &Alles skoon</translation> + <translation>Clear &All</translation> </message> <message> <source>&Verify Message</source> - <translation>&Verifieer Boodskap</translation> + <translation>&Verify Message</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>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!</translation> + </message> + <message> + <source>The Bitcoin address the message was signed with</source> + <translation>The Bitcoin address the message was signed with</translation> + </message> + <message> + <source>The signed message to verify</source> + <translation>The signed message to verify</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>The signature given when the message was signed</translation> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation>Verify the message to ensure it was signed with the specified Bitcoin address</translation> </message> <message> <source>Verify &Message</source> - <translation>Verifieer &Boodskap</translation> + <translation>Verify &Message</translation> + </message> + <message> + <source>Reset all verify message fields</source> + <translation>Reset all verify message fields</translation> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation>Click "Sign Message" to generate signature</translation> + </message> + <message> + <source>The entered address is invalid.</source> + <translation>The entered address is invalid.</translation> + </message> + <message> + <source>Please check the address and try again.</source> + <translation>Please check the address and try again.</translation> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation>The entered address does not refer to a key.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation>Wallet unlock was cancelled.</translation> + </message> + <message> + <source>No error</source> + <translation>No error</translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation>Private key for the entered address is not available.</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Message signing failed.</translation> </message> <message> <source>Message signed.</source> - <translation>Boodskap geteken.</translation> + <translation>Message signed.</translation> + </message> + <message> + <source>The signature could not be decoded.</source> + <translation>The signature could not be decoded.</translation> + </message> + <message> + <source>Please check the signature and try again.</source> + <translation>Please check the signature and try again.</translation> + </message> + <message> + <source>The signature did not match the message digest.</source> + <translation>The signature did not match the message digest.</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>Message verification failed.</translation> </message> <message> <source>Message verified.</source> - <translation>Boodskap geverifieer.</translation> + <translation>Message verified.</translation> </message> </context> <context> @@ -1775,246 +2694,422 @@ word die fooi eweredig verdeel.</translation> </context> <context> <name>TransactionDesc</name> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> + <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>conflicted with a transaction with %1 confirmations</source> + <translation>conflicted with a transaction with %1 confirmations</translation> + </message> + <message> + <source>0/unconfirmed, %1</source> + <translation>0/unconfirmed, %1</translation> + </message> + <message> + <source>in memory pool</source> + <translation>in memory pool</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>not in memory pool</translation> + </message> + <message> + <source>abandoned</source> + <translation>abandoned</translation> + </message> + <message> + <source>%1/unconfirmed</source> + <translation>%1/unconfirmed</translation> + </message> + <message> + <source>%1 confirmations</source> + <translation>%1 confirmations</translation> + </message> + <message> + <source>Status</source> + <translation>Status</translation> + </message> <message> <source>Date</source> - <translation>Datum</translation> + <translation>Date</translation> + </message> + <message> + <source>Source</source> + <translation>Source</translation> + </message> + <message> + <source>Generated</source> + <translation>Generated</translation> </message> <message> <source>From</source> - <translation>Van</translation> + <translation>From</translation> </message> <message> <source>unknown</source> - <translation>onbekend</translation> + <translation>unknown</translation> </message> <message> <source>To</source> - <translation>Na</translation> + <translation>To</translation> </message> <message> <source>own address</source> - <translation>eie adres</translation> + <translation>own address</translation> </message> <message> <source>watch-only</source> - <translation>kyk-net</translation> + <translation>watch-only</translation> </message> <message> <source>label</source> - <translation>etiket</translation> + <translation>label</translation> </message> <message> <source>Credit</source> - <translation>Krediet</translation> + <translation>Credit</translation> + </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>matures in %n more block</numerusform><numerusform>matures in %n more blocks</numerusform></translation> </message> <message> <source>not accepted</source> - <translation>nie aanvaar nie</translation> + <translation>not accepted</translation> </message> <message> <source>Debit</source> - <translation>Debiet</translation> + <translation>Debit</translation> </message> <message> <source>Total debit</source> - <translation>Totale debiet</translation> + <translation>Total debit</translation> </message> <message> <source>Total credit</source> - <translation>Totale crediet</translation> + <translation>Total credit</translation> </message> <message> <source>Transaction fee</source> - <translation>Transaksie fooi</translation> + <translation>Transaction fee</translation> </message> <message> <source>Net amount</source> - <translation>Netto bedrag</translation> + <translation>Net amount</translation> </message> <message> <source>Message</source> - <translation>Boodskap</translation> + <translation>Message</translation> </message> <message> <source>Comment</source> - <translation>Kommentaar</translation> + <translation>Comment</translation> </message> <message> <source>Transaction ID</source> - <translation>Transaksie ID</translation> + <translation>Transaction ID</translation> </message> <message> <source>Transaction total size</source> - <translation>Transaksie totale grootte</translation> + <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> + <message> + <source> (Certificate was not verified)</source> + <translation> (Certificate was not verified)</translation> + </message> + <message> + <source>Merchant</source> + <translation>Merchant</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>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.</translation> + </message> + <message> + <source>Debug information</source> + <translation>Debug information</translation> </message> <message> <source>Transaction</source> - <translation>Transaksie</translation> + <translation>Transaction</translation> + </message> + <message> + <source>Inputs</source> + <translation>Inputs</translation> </message> <message> <source>Amount</source> - <translation>Bedrag</translation> + <translation>Amount</translation> </message> <message> <source>true</source> - <translation>waar</translation> + <translation>true</translation> </message> <message> <source>false</source> - <translation>onwaar</translation> + <translation>false</translation> </message> </context> <context> <name>TransactionDescDialog</name> - </context> + <message> + <source>This pane shows a detailed description of the transaction</source> + <translation>This pane shows a detailed description of the transaction</translation> + </message> + <message> + <source>Details for %1</source> + <translation>Details for %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> <source>Date</source> - <translation>Datum</translation> + <translation>Date</translation> </message> <message> <source>Type</source> - <translation>Tipe</translation> + <translation>Type</translation> </message> <message> <source>Label</source> - <translation>Etiket</translation> + <translation>Label</translation> + </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> + <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>Unconfirmed</source> + <translation>Unconfirmed</translation> + </message> + <message> + <source>Abandoned</source> + <translation>Abandoned</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation>Confirming (%1 of %2 recommended confirmations)</translation> + </message> + <message> + <source>Confirmed (%1 confirmations)</source> + <translation>Confirmed (%1 confirmations)</translation> + </message> + <message> + <source>Conflicted</source> + <translation>Conflicted</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation>Immature (%1 confirmations, will be available after %2)</translation> + </message> + <message> + <source>Generated but not accepted</source> + <translation>Generated but not accepted</translation> </message> <message> <source>Received with</source> - <translation>Ontvang met</translation> + <translation>Received with</translation> </message> <message> <source>Received from</source> - <translation>Ontvang van</translation> + <translation>Received from</translation> </message> <message> <source>Sent to</source> - <translation>Gestuur na</translation> + <translation>Sent to</translation> </message> <message> <source>Payment to yourself</source> - <translation>Betalings Aan/na jouself</translation> + <translation>Payment to yourself</translation> </message> <message> <source>Mined</source> - <translation>Gemyn</translation> + <translation>Mined</translation> </message> <message> <source>watch-only</source> - <translation>kyk-net</translation> + <translation>watch-only</translation> </message> <message> <source>(n/a)</source> - <translation>(n.v.t)</translation> + <translation>(n/a)</translation> </message> <message> <source>(no label)</source> - <translation>(geen etiket)</translation> + <translation>(no label)</translation> + </message> + <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation>Transaction status. Hover over this field to show number of confirmations.</translation> </message> <message> <source>Date and time that the transaction was received.</source> - <translation>Datum en tyd wat die transaksie ontvang was.</translation> + <translation>Date and time that the transaction was received.</translation> </message> <message> <source>Type of transaction.</source> - <translation>Tipe transaksie.</translation> + <translation>Type of transaction.</translation> </message> - </context> + <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Whether or not a watch-only address is involved in this transaction.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>User-defined intent/purpose of the transaction.</translation> + </message> + <message> + <source>Amount removed from or added to balance.</source> + <translation>Amount removed from or added to balance.</translation> + </message> +</context> <context> <name>TransactionView</name> <message> <source>All</source> - <translation>Alles</translation> + <translation>All</translation> </message> <message> <source>Today</source> - <translation>Vandag</translation> + <translation>Today</translation> </message> <message> <source>This week</source> - <translation>Hierdie week</translation> + <translation>This week</translation> </message> <message> <source>This month</source> - <translation>Hierdie maand</translation> + <translation>This month</translation> </message> <message> <source>Last month</source> - <translation>Verlede maand</translation> + <translation>Last month</translation> </message> <message> <source>This year</source> - <translation>Hierdie jaar</translation> + <translation>This year</translation> </message> <message> <source>Range...</source> - <translation>Reeks...</translation> + <translation>Range...</translation> </message> <message> <source>Received with</source> - <translation>Ontvang met</translation> + <translation>Received with</translation> </message> <message> <source>Sent to</source> - <translation>Gestuur na</translation> + <translation>Sent to</translation> </message> <message> <source>To yourself</source> - <translation>Aan/na jouself</translation> + <translation>To yourself</translation> </message> <message> <source>Mined</source> - <translation>Gemyn</translation> + <translation>Mined</translation> </message> <message> <source>Other</source> - <translation>Ander</translation> + <translation>Other</translation> + </message> + <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Enter address, transaction id, or label to search</translation> </message> <message> <source>Min amount</source> - <translation>Min bedrag</translation> + <translation>Min amount</translation> + </message> + <message> + <source>Abandon transaction</source> + <translation>Abandon transaction</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>Increase transaction fee</translation> </message> <message> <source>Copy address</source> - <translation>Maak kopie van adres</translation> + <translation>Copy address</translation> </message> <message> <source>Copy label</source> - <translation>Kopieer etiket</translation> + <translation>Copy label</translation> </message> <message> <source>Copy amount</source> - <translation>Kopieer bedrag</translation> + <translation>Copy amount</translation> </message> <message> <source>Copy transaction ID</source> - <translation>Kopieer transaksie ID</translation> + <translation>Copy transaction ID</translation> + </message> + <message> + <source>Copy raw transaction</source> + <translation>Copy raw transaction</translation> + </message> + <message> + <source>Copy full transaction details</source> + <translation>Copy full transaction details</translation> + </message> + <message> + <source>Edit label</source> + <translation>Edit label</translation> + </message> + <message> + <source>Show transaction details</source> + <translation>Show transaction details</translation> + </message> + <message> + <source>Export Transaction History</source> + <translation>Export Transaction History</translation> </message> <message> <source>Comma separated file (*.csv)</source> - <translation>Koma geskeide lêer (*.csv)</translation> + <translation>Comma separated file (*.csv)</translation> </message> <message> <source>Confirmed</source> - <translation>Bevestig</translation> + <translation>Confirmed</translation> + </message> + <message> + <source>Watch-only</source> + <translation>Watch-only</translation> </message> <message> <source>Date</source> - <translation>Datum</translation> + <translation>Date</translation> </message> <message> <source>Type</source> - <translation>Tipe</translation> + <translation>Type</translation> </message> <message> <source>Label</source> - <translation>Etiket</translation> + <translation>Label</translation> </message> <message> <source>Address</source> - <translation>Adres</translation> + <translation>Address</translation> </message> <message> <source>ID</source> @@ -2022,133 +3117,627 @@ word die fooi eweredig verdeel.</translation> </message> <message> <source>Exporting Failed</source> - <translation>Uitvoering Misluk</translation> + <translation>Exporting Failed</translation> + </message> + <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation>There was an error trying to save the transaction history to %1.</translation> + </message> + <message> + <source>Exporting Successful</source> + <translation>Exporting Successful</translation> + </message> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>The transaction history was successfully saved to %1.</translation> </message> <message> <source>Range:</source> - <translation>Reeks:</translation> + <translation>Range:</translation> </message> <message> <source>to</source> - <translation>aan</translation> + <translation>to</translation> </message> </context> <context> <name>UnitDisplayStatusBarControl</name> - </context> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Unit to show amounts in. Click to select another unit.</translation> + </message> +</context> <context> <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>Close wallet</translation> + </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Are you sure you wish to close the wallet <i>%1</i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</translation> + </message> </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Create a new wallet</translation> + </message> +</context> <context> <name>WalletModel</name> <message> <source>Send Coins</source> - <translation>Stuur Munstukke</translation> + <translation>Send Coins</translation> + </message> + <message> + <source>Fee bump error</source> + <translation>Fee bump error</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation>Increasing transaction fee failed</translation> + </message> + <message> + <source>Do you want to increase the fee?</source> + <translation>Do you want to increase the fee?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Do you want to draft a transaction with fee increase?</translation> + </message> + <message> + <source>Current fee:</source> + <translation>Current fee:</translation> + </message> + <message> + <source>Increase:</source> + <translation>Increase:</translation> </message> <message> <source>New fee:</source> - <translation>Nuwe fooi:</translation> + <translation>New fee:</translation> </message> - </context> + <message> + <source>Confirm fee bump</source> + <translation>Confirm fee bump</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Can't draft transaction.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT copied</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Can't sign transaction.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Could not commit transaction</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> +</context> <context> <name>WalletView</name> <message> <source>&Export</source> - <translation>&Uitvoer</translation> + <translation>&Export</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation>Voer inligting uit van die huidige blad na n lêer</translation> + <translation>Export the data in the current tab to a file</translation> </message> - </context> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>Backup Wallet</translation> + </message> + <message> + <source>Wallet Data (*.dat)</source> + <translation>Wallet Data (*.dat)</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>Backup Failed</translation> + </message> + <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation>There was an error trying to save the wallet data to %1.</translation> + </message> + <message> + <source>Backup Successful</source> + <translation>Backup Successful</translation> + </message> + <message> + <source>The wallet data was successfully saved to %1.</source> + <translation>The wallet data was successfully saved to %1.</translation> + </message> + <message> + <source>Cancel</source> + <translation>Cancel</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>Distributed under the MIT software license, see the accompanying file %s or %s</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Prune configured below the minimum of %d MiB. Please use a higher number.</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>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Pruning blockstore...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Unable to start HTTP server. See debug log for details.</translation> + </message> + <message> + <source>The %s developers</source> + <translation>The %s developers</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Cannot obtain a lock on data directory %s. %s is probably already running.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Cannot provide specific connections and have addrman find outgoing connections at the same.</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>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</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> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Please contribute if you find %s useful. Visit %s for further information about the software.</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>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</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>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation> + </message> + <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>This is the transaction fee you may discard if change is smaller than dust at this level</translation> + </message> + <message> + <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <translation>Unable to replay blocks. You will need to rebuild the database using -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>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</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>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation> + </message> + <message> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool must be at least %d MB</translation> + </message> + <message> + <source>Cannot resolve -%s address: '%s'</source> + <translation>Cannot resolve -%s address: '%s'</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>Change index out of range</translation> + </message> + <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Config setting for %s only applied on %s network when in [%s] section.</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation>Corrupted block database detected</translation> + </message> + <message> + <source>Could not find asmap file %s</source> + <translation>Could not find asmap file %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Could not parse asmap file %s</translation> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation>Do you want to rebuild the block database now?</translation> + </message> + <message> + <source>Error initializing block database</source> + <translation>Error initializing block database</translation> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation>Error initializing wallet database environment %s!</translation> + </message> + <message> <source>Error loading %s</source> - <translation>Fout met laai %s</translation> + <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> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Error loading %s: Wallet requires newer version of %s</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>Error loading block database</translation> + </message> + <message> + <source>Error opening block database</source> + <translation>Error opening block database</translation> + </message> + <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> + </message> + <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Failed to rescan the wallet during initialization</translation> </message> <message> <source>Importing...</source> - <translation>Invoer proses tans besig..</translation> + <translation>Importing...</translation> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>Initialization sanity check failed. %s is shutting down.</translation> + </message> + <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Invalid P2P permission: '%s'</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Invalid amount for -%s=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -discardfee=<amount>: '%s'</source> + <translation>Invalid amount for -discardfee=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> + <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>Unknown address type '%s'</source> + <translation>Unknown address type '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Unknown change type '%s'</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> + <message> + <source>Loading banlist...</source> + <translation>Loading banlist...</translation> + </message> + <message> + <source>Not enough file descriptors available.</source> + <translation>Not enough file descriptors available.</translation> + </message> + <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Prune cannot be configured with a negative value.</translation> + </message> + <message> + <source>Prune mode is incompatible with -txindex.</source> + <translation>Prune mode is incompatible with -txindex.</translation> + </message> + <message> + <source>Replaying blocks...</source> + <translation>Replaying blocks...</translation> + </message> + <message> + <source>Rewinding blocks...</source> + <translation>Rewinding blocks...</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>The source code is available from %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <translation>Transaction fee and change calculation failed</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <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 logging category %s=%s.</source> + <translation>Unsupported logging category %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Upgrading UTXO database</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>User Agent comment (%s) contains unsafe characters.</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>Verifying blocks...</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Wallet needed to be rewritten: restart %s to complete</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Error: Listening for incoming connections failed (listen returned error %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>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>The transaction amount is too small to send after the fee has been deducted</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>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Error reading from database, shutting down.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Error upgrading chainstate database</translation> + </message> + <message> + <source>Error: Disk space is low for %s</source> + <translation>Error: Disk space is low for %s</translation> + </message> + <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Invalid -onion address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Invalid -proxy address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Invalid netmask specified in -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Need to specify a port with -whitebind: '%s'</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Prune mode is incompatible with -blockfilterindex.</translation> + </message> + <message> + <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> + <translation>Reducing -maxconnections from %d to %d, because of system limitations.</translation> + </message> + <message> + <source>Section [%s] is not recognized.</source> + <translation>Section [%s] is not recognized.</translation> </message> <message> <source>Signing transaction failed</source> - <translation>Teken van transaksie het misluk</translation> + <translation>Signing transaction failed</translation> + </message> + <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Specified -walletdir "%s" does not exist</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Specified -walletdir "%s" is a relative path</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Specified -walletdir "%s" is not a directory</translation> + </message> + <message> + <source>The specified config file %s does not exist +</source> + <translation>The specified config file %s does not exist +</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>The transaction amount is too small to pay the fee</translation> </message> <message> <source>This is experimental software.</source> - <translation>Dié is eksperimentele sagteware.</translation> + <translation>This is experimental software.</translation> </message> <message> <source>Transaction amount too small</source> - <translation>Transaksie bedrag te klein</translation> + <translation>Transaction amount too small</translation> </message> <message> <source>Transaction too large</source> - <translation>Transaksie te groot</translation> + <translation>Transaction too large</translation> + </message> + <message> + <source>Unable to bind to %s on this computer (bind returned error %s)</source> + <translation>Unable to bind to %s on this computer (bind returned error %s)</translation> + </message> + <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>Unable to create the PID file '%s': %s</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>Unable to generate initial keys</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Unknown -blockfilterindex value %s.</translation> </message> <message> <source>Verifying wallet(s)...</source> - <translation>Besig met verifieer van beursie(s)...</translation> + <translation>Verifying wallet(s)...</translation> + </message> + <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Warning: unknown new rules activated (versionbit %i)</translation> + </message> + <message> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation> + </message> + <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>This is the transaction fee you may pay when fee estimates are not available.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</translation> </message> <message> <source>%s is set very high!</source> - <translation>%s is baie hoog gestel!</translation> + <translation>%s is set very high!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Error loading wallet %s. Duplicate -wallet filename specified.</translation> </message> <message> <source>Starting network threads...</source> - <translation>Begin tans netwerkdrade...</translation> + <translation>Starting network threads...</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>The wallet will avoid paying less than the minimum relay fee.</translation> </message> <message> <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation>Dit is die minimum transaksie fooi wat u betaal op elke transaksie.</translation> + <translation>This is the minimum transaction fee you pay on every transaction.</translation> </message> <message> <source>This is the transaction fee you will pay if you send a transaction.</source> - <translation>Dit is die transaksie fooi wat u sal betaal as u 'n transaksie stuur.</translation> + <translation>This is the transaction fee you will pay if you send a transaction.</translation> </message> <message> <source>Transaction amounts must not be negative</source> - <translation>Transaksies bedrae moet nie negatief wees nie</translation> + <translation>Transaction amounts must not be negative</translation> </message> <message> <source>Transaction has too long of a mempool chain</source> - <translation>Transaksie se mempool ketting is te lank</translation> + <translation>Transaction has too long of a mempool chain</translation> </message> <message> <source>Transaction must have at least one recipient</source> - <translation>Transaksie moet ten minste een ontvanger hê</translation> + <translation>Transaction must have at least one recipient</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation>Onbekende netwerk gespesifiseer in -onlynet: '%s'</translation> + <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> <source>Insufficient funds</source> - <translation>Onvoldoende fondse</translation> + <translation>Insufficient funds</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>Laai blok indeks...</translation> + <translation>Loading block index...</translation> </message> <message> <source>Loading wallet...</source> - <translation>Laai beursie...</translation> + <translation>Loading wallet...</translation> </message> <message> <source>Cannot downgrade wallet</source> - <translation>Kan nie beursie afgradeer nie</translation> + <translation>Cannot downgrade wallet</translation> </message> <message> <source>Rescanning...</source> - <translation>Word herskandeer...</translation> + <translation>Rescanning...</translation> </message> <message> <source>Done loading</source> - <translation>Klaar gelaai</translation> + <translation>Done loading</translation> </message> </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_am.ts b/src/qt/locale/bitcoin_am.ts index f78d4b970c..547ee1dde6 100644 --- a/src/qt/locale/bitcoin_am.ts +++ b/src/qt/locale/bitcoin_am.ts @@ -311,6 +311,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -330,14 +333,6 @@ </context> <context> <name>ReceiveRequestDialog</name> - <message> - <source>Address</source> - <translation>አድራሻ</translation> - </message> - <message> - <source>Label</source> - <translation>መለያ ስም</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts index 0d138d353c..dbe680ad5c 100644 --- a/src/qt/locale/bitcoin_ar.ts +++ b/src/qt/locale/bitcoin_ar.ts @@ -70,8 +70,10 @@ <translation>هذه هي عناوين البيتكوين لإرسال المدفوعات. دائما تحقق من المبلغ وعنوان المستلم قبل الإرسال.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>هذه هي عناوين البيتكوين الخاصة بك لإستلام المدفوعات. استخدم زر "إنشاء عنوان استلام جديد" في علامة التبويب "إستلام" لإنشاء عناوين جديدة.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>هذه هي عناوين بتكوين الخاصة بك لتلقي المدفوعات. استخدم الزر "إنشاء عنوان استلام جديد" في علامة تبويب الاستلام لإنشاء عناوين جديدة. +التوقيع ممكن فقط مع عناوين من النوع "قديم".</translation> </message> <message> <source>&Copy Address</source> @@ -184,6 +186,10 @@ <translation>ادخل كملة المرور القديمة وكلمة المرور الجديدة للمحفظة.</translation> </message> <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>تذكر أن تشفير محفظتك لا يحمي البيتكوين الخاصة بك بشكل كامل من السرقة من قبل البرامج الخبيثةالتي تصيب حاسوبك</translation> + </message> + <message> <source>Wallet to be encrypted</source> <translation>سوف يتم تشفير محفظتك</translation> </message> @@ -193,7 +199,7 @@ </message> <message> <source>Your wallet is now encrypted. </source> - <translation>تم تشفير محفظتك.</translation> + <translation>محفظتك ألان مشفرة</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> @@ -437,6 +443,10 @@ <source>Processing blocks on disk...</source> <translation>معالجة الكتل على القرص...</translation> </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Processed %n blocks of transaction history.</numerusform><numerusform>Processed %n block of transaction history.</numerusform><numerusform>Processed %n blocks of transaction history.</numerusform><numerusform>Processed %n blocks of transaction history.</numerusform><numerusform>Processed %n blocks of transaction history.</numerusform><numerusform>تمت معالجة٪ n من كتل سجل المعاملات.</numerusform></translation> + </message> <message> <source>%1 behind</source> <translation>خلف %1</translation> @@ -466,6 +476,30 @@ <translation>محدث</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>& تحميل PSBT من ملف ...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>تحميل معاملة بتكوين الموقعة جزئيًا</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>تحميل PSBT من الحافظة ...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>تحميل معاملة بتكوين الموقعة جزئيًا من الحافظة</translation> + </message> + <message> + <source>Node window</source> + <translation>نافذة Node </translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>افتح وحدة التحكم في تصحيح أخطاء node والتشخيص</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&عناوين الإرسال</translation> </message> @@ -474,6 +508,10 @@ <translation>&عناوين الإستقبال</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>افتح عملة بيتكوين: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>افتح المحفظة</translation> </message> @@ -490,10 +528,26 @@ <translation>اغلق المحفظة</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>إغلاق جميع المحافظ ...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>إغلاق جميع المحافظ ...</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>بين اشارة المساعدة %1 للحصول على قائمة من خيارات اوامر البت كوين المحتملة </translation> </message> <message> + <source>&Mask values</source> + <translation>& إخفاء القيم</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>إخفاء القيم في علامة التبويب نظرة عامة</translation> + </message> + <message> <source>default wallet</source> <translation>المحفظة الإفتراضية</translation> </message> @@ -534,6 +588,10 @@ <translation>خطأ: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>تحذير: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>التاريخ %1 @@ -599,8 +657,12 @@ <translation>المحفظة <b>مشفرة</b> و <b>مقفلة</b> حاليا</translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>خطأ فادح حدث . لا يمكن اتمام بيتكوين بامان سيتم الخروج</translation> + <source>Original message:</source> + <translation>الرسالة الأصلية:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>حدث خطأ فادح. لم يعد بإمكان %1 المتابعة بأمان وسيتم الإنهاء.</translation> </message> </context> <context> @@ -756,10 +818,62 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>جاري إنشاء المحفظة<b>%1</b>.......</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>فشل إنشاء المحفظة</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>تحذير إنشاء محفظة</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> <message> + <source>Create Wallet</source> + <translation>إنشاء محفظة</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>إسم المحفظة</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>شفر المحفظة. المحفظة سيتم تشفيرها بإستخدام كلمة مرور من إختيارك.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>تشفير محفظة</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>تعطيل المفاتيح الخاصة لهذه المحفظة. لن تحتوي المحافظ ذات المفاتيح الخاصة المعطلة على مفاتيح خاصة ولا يمكن أن تحتوي على مفتاح HD أو مفاتيح خاصة مستوردة. هذا مثالي لمحافظ مشاهدة فقط فقط.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>إيقاف المفاتيح الخاصة</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>اصنع محفظة فارغة. لا تحتوي المحافظ الفارغة في البداية على مفاتيح خاصة أو نصوص. يمكن استيراد المفاتيح والعناوين الخاصة، أو يمكن تعيين مصدر HD في وقت لاحق.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>أنشئ محفظة فارغة</translation> + </message> + <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>استخدم الواصفات لإدارة scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>المحفظة الوصفية</translation> + </message> + <message> <source>Create</source> <translation>إنشاء</translation> </message> @@ -803,6 +917,14 @@ <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> @@ -868,6 +990,10 @@ <translation>عند النقر على "موافق" ، سيبدأ %1 في تنزيل ومعالجة سلسلة الكتل %4 الكاملة (%2 جيجابايت) بدءًا من المعاملات الأقدم في %3 عند تشغيل %4 في البداية.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>تتطلب العودة إلى هذا الإعداد إعادة تنزيل سلسلة الكتل بالكامل. من الأسرع تنزيل السلسلة الكاملة أولاً وتقليمها لاحقًا. تعطيل بعض الميزات المتقدمة.</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>تُعد هذه المزامنة الأولية أمرًا شاقًا للغاية، وقد تعرض جهاز الكمبيوتر الخاص بك للمشاكل الذي لم يلاحظها أحد سابقًا. في كل مرة تقوم فيها بتشغيل %1، سيتابع التحميل من حيث تم التوقف.</translation> </message> @@ -888,6 +1014,10 @@ <translation>بتكوين</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>تجاهل الكتل بعد التحقق ، باستثناء أحدث %1 جيجابايت (تقليم)</translation> + </message> + <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <translation>سيتم تخزين %1 جيجابايت على الأقل من البيانات في هذا الدليل، وستنمو مع الوقت.</translation> </message> @@ -958,10 +1088,18 @@ <source>Hide</source> <translation>إخفاء</translation> </message> - </context> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>مجهول. مزامنة الرؤوس (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>افتح بتكوين URI</translation> + </message> + <message> <source>URI:</source> <translation>العنوان:</translation> </message> @@ -969,6 +1107,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>فشل فتح محفظة</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>تحذير محفظة مفتوحة</translation> + </message> + <message> <source>default wallet</source> <translation>محفظة إفتراضية</translation> </message> @@ -1004,12 +1150,12 @@ <translation>عدد مؤشرات التحقق من البرنامج النصي</translation> </message> <message> - <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> - <translation>إظهار ما إذا كان وكيل SOCKS5 الافتراضي الموفر تم استخدامه للوصول إلى النظراء عبر نوع الشبكة هذا.</translation> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <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>استخدام وكيل SOCKS5 منفصل للوصول إلى الأقران عبر خدمات Tor المخفية:</translation> + <source>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> + <translation>إظهار ما إذا كان وكيل SOCKS5 الافتراضي الموفر تم استخدامه للوصول إلى النظراء عبر نوع الشبكة هذا.</translation> </message> <message> <source>Hide the icon from the system tray.</source> @@ -1044,10 +1190,22 @@ <translation>&الشبكة</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>تقليم وحظر التخزين لـ</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>MiB</source> <translation>ميجا بايت</translation> </message> @@ -1116,10 +1274,6 @@ <translation>تور</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> @@ -1144,6 +1298,10 @@ <translation>واجهة المستخدم &اللغة:</translation> </message> <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>سيسري هذا الإعداد بعد إعادة تشغيل %1.</translation> + </message> + <message> <source>&Unit to show amounts in:</source> <translation>الوحدة لإظهار المبالغ فيها:</translation> </message> @@ -1156,10 +1314,22 @@ <translation>ما اذا أردت إظهار ميزات التحكم في العملة أم لا.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>اتصل بشبكة بتكوين من خلال وكيل SOCKS5 منفصل لخدمات Tor onion.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>استخدم بروكسي SOCKS5 منفصل للوصول إلى الأقران عبر خدمات Tor onion:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>العناوين (URL) لجهات خارجية</translation> </message> <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>يتم تجاوز الخيارات المعينة في مربع الحوار هذا بواسطة سطر الأوامر أو في ملف التكوين:</translation> + </message> + <message> <source>&OK</source> <translation>تم</translation> </message> @@ -1192,6 +1362,10 @@ <translation>إعداد الخيارات</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>يتم استخدام ملف التكوين لتحديد خيارات المستخدم المتقدمة التي تتجاوز إعدادات واجهة المستخدم الرسومية. بالإضافة إلى ذلك ، ستتجاوز أي خيارات سطر أوامر ملف التكوين هذا.</translation> + </message> + <message> <source>Error</source> <translation>خطأ</translation> </message> @@ -1282,8 +1456,99 @@ <source>Current total balance in watch-only addresses</source> <translation>الرصيد الإجمالي الحالي في العناوين المشاهدة فقط</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>تم تنشيط وضع الخصوصية لعلامة التبويب "نظرة عامة". للكشف عن القيم ، قم بإلغاء تحديد الإعدادات-> إخفاء القيم.</translation> + </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>حوار</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>تسجيل Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>بث TX</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>نسخ إلى الحافظة</translation> + </message> + <message> + <source>Save...</source> + <translation>حفظ...</translation> + </message> + <message> + <source>Close</source> + <translation>إغلاق</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>فشل تحميل المعاملة: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>فشل توقيع المعاملة: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>تعذر توقيع المزيد من المدخلات.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>تم توقيع %1 إدخالات، ولكن لا تزال هناك حاجة إلى المزيد من التوقيعات.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>تم توقيع المعاملة بنجاح. المعاملة جاهزة للبث.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>خطأ غير معروف في معالجة المعاملة.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>تم بث المعاملة بنجاح! معرّف المعاملة: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>فشل بث المعاملة: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>نسخ PSBT إلى الحافظة.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>حفظ بيانات المعاملات</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>معاملة موقعة جزئيًا (ثنائي) (* .psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>تم حفظ PSBT على القرص.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>* يرسل %1 إلى %2</translation> + </message> + <message> + <source>Total Amount</source> + <translation>القيمة الإجمالية</translation> + </message> + <message> + <source>or</source> + <translation>أو</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1486,10 +1751,6 @@ <translation>سلسلة الكتل</translation> </message> <message> - <source>Current number of blocks</source> - <translation>عدد الكتل الحالي</translation> - </message> - <message> <source>Memory Pool</source> <translation>تجمع الذاكرة</translation> </message> @@ -1502,6 +1763,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> @@ -1526,10 +1795,6 @@ <translation>حدد نظير لعرض معلومات مفصلة.</translation> </message> <message> - <source>Whitelisted</source> - <translation>اللائحة البيضاء</translation> - </message> - <message> <source>Direction</source> <translation>جهة</translation> </message> @@ -1554,6 +1819,10 @@ <translation>وكيل المستخدم</translation> </message> <message> + <source>Node window</source> + <translation>نافذة Node </translation> + </message> + <message> <source>Decrease font size</source> <translation>تصغير حجم الخط</translation> </message> @@ -1562,12 +1831,12 @@ <translation>تكبير حجم الخط</translation> </message> <message> - <source>Services</source> - <translation>خدمات</translation> + <source>Permissions</source> + <translation>اذونات</translation> </message> <message> - <source>Ban Score</source> - <translation>نقاط الحظر</translation> + <source>Services</source> + <translation>خدمات</translation> </message> <message> <source>Connection Time</source> @@ -1690,6 +1959,10 @@ <translation>تم تعطيل نشاط الشبكة</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>تنفيذ الأوامر بدون محفظة </translation> + </message> + <message> <source>(node id: %1)</source> <translation>(معرف العقدة: %1)</translation> </message> @@ -1710,14 +1983,6 @@ <translation>خارجي</translation> </message> <message> - <source>Yes</source> - <translation>نعم</translation> - </message> - <message> - <source>No</source> - <translation>لا</translation> - </message> - <message> <source>Unknown</source> <translation>غير معرف</translation> </message> @@ -1753,6 +2018,10 @@ <translation>مبلغ اختياري للطلب. اترك هذا فارغًا أو صفراً لعدم طلب مبلغ محدد.</translation> </message> <message> + <source>&Create new receiving address</source> + <translation>و إنشاء عناوين استقبال جديدة</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>مسح كل حقول النموذج المطلوبة</translation> </message> @@ -1796,12 +2065,32 @@ <source>Copy amount</source> <translation>نسخ الكمية</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation> يمكن فتح المحفظة.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>رمز كيو ار</translation> + <source>Request payment to ...</source> + <translation>طلب دفع ل ...</translation> + </message> + <message> + <source>Address:</source> + <translation>العناوين:</translation> + </message> + <message> + <source>Amount:</source> + <translation>القيمة :</translation> + </message> + <message> + <source>Message:</source> + <translation>الرسائل</translation> + </message> + <message> + <source>Wallet:</source> + <translation>المحفظة:</translation> </message> <message> <source>Copy &URI</source> @@ -1823,30 +2112,6 @@ <source>Payment information</source> <translation>معلومات الدفع</translation> </message> - <message> - <source>URI</source> - <translation> URI</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> </context> <context> <name>RecentRequestsTableModel</name> @@ -2050,6 +2315,18 @@ <translation>هل أنت متأكد من أنك تريد أن ترسل؟</translation> </message> <message> + <source>Create Unsigned</source> + <translation>إنشاء غير موقع</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>حفظ بيانات المعاملات</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>معاملة موقعة جزئيًا (ثنائي) (* .psbt)</translation> + </message> + <message> <source>or</source> <translation>أو</translation> </message> @@ -2066,10 +2343,18 @@ <translation>لا يشير إلى الإستبدال بواسطة الرسوم، BIP-125.</translation> </message> <message> + <source>Total Amount</source> + <translation>القيمة الإجمالية</translation> + </message> + <message> <source>Confirm send coins</source> <translation>تأكيد الإرسال Coins</translation> </message> <message> + <source>Send</source> + <translation>إرسال</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>عنوان المستلم غير صالح. يرجى إعادة الفحص.</translation> </message> @@ -2775,12 +3060,16 @@ <source>Close wallet</source> <translation>اغلق المحفظة</translation> </message> + <message> + <source>Close all wallets</source> + <translation>إغلاق جميع المحافظ ...</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>لا يوجد محفظة تم تحميلها.</translation> + <source>Create a new wallet</source> + <translation>إنشاء محفظة جديدة</translation> </message> </context> <context> @@ -2841,6 +3130,10 @@ <translation>استخراج البيانات في علامة التبويب الحالية إلى ملف</translation> </message> <message> + <source>Error</source> + <translation>خطأ</translation> + </message> + <message> <source>Backup Wallet</source> <translation>نسخ احتياط للمحفظة</translation> </message> @@ -2868,10 +3161,6 @@ <context> <name>bitcoin-core</name> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>خطأ: حدث خطأ داخلي فادح، راجع debug.log للحصول على التفاصيل</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>تجريد مخزن الكتل...</translation> </message> @@ -2896,11 +3185,6 @@ <translation>يرجى المساهمة إذا وجدت %s مفيداً. تفضل بزيارة %s لمزيد من المعلومات حول البرنامج.</translation> </message> <message> - <source>%s corrupt, salvage failed</source> - <translation> -%s تالف, فشل الانقاذ.</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-الحد الأقصى للذاكرة على الأقل %d ميغابايت</translation> </message> @@ -3061,14 +3345,6 @@ <translation>التحقق من المحفظة (المحافظ)...</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>إزالة جميع المعاملات من المحفظة...</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>تحذير: ملف المحفظة فاسد ، تم انقاذ البيانات! تم حفظ %s الأصلي ك %s في %s؛ إذا كان رصيدك أو كانت معاملاتك غير صحيحة، فيجب عليك الإستعادة من نسخة احتياطية.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s عالٍ جداً</translation> </message> diff --git a/src/qt/locale/bitcoin_be.ts b/src/qt/locale/bitcoin_be.ts index bb0c17901f..f2a022220f 100644 --- a/src/qt/locale/bitcoin_be.ts +++ b/src/qt/locale/bitcoin_be.ts @@ -661,6 +661,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -709,34 +712,26 @@ <source>Copy amount</source> <translation>Капіяваць колькасць</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> - <message> - <source>Copy &Address</source> - <translation>Капіяваць адрас</translation> - </message> <message> - <source>Address</source> - <translation>Адрас</translation> - </message> - <message> - <source>Amount</source> - <translation>Колькасць</translation> + <source>Could not unlock wallet.</source> + <translation>Немагчыма разблакаваць гаманец</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Label</source> - <translation>Метка</translation> + <source>Amount:</source> + <translation>Колькасць:</translation> </message> <message> - <source>Message</source> - <translation>Паведамленне</translation> + <source>Message:</source> + <translation>Паведамленне:</translation> </message> <message> - <source>Wallet</source> - <translation>Гаманец</translation> + <source>Copy &Address</source> + <translation>Капіяваць адрас</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1157,6 +1152,10 @@ <source>Export the data in the current tab to a file</source> <translation>Экспартаваць гэтыя звесткі у файл</translation> </message> + <message> + <source>Error</source> + <translation>Памылка</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts index 694c1b1008..ed59d98664 100644 --- a/src/qt/locale/bitcoin_bg.ts +++ b/src/qt/locale/bitcoin_bg.ts @@ -132,6 +132,10 @@ <translation>Повтори парола</translation> </message> <message> + <source>Show passphrase</source> + <translation>Показване на парола</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Криптирай портфейл</translation> </message> @@ -172,6 +176,14 @@ <translation>портфейлa е шифрован</translation> </message> <message> + <source>Wallet to be encrypted</source> + <translation>Портфейл за криптиране</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Вашият портфейл сега е криптиран.</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> @@ -438,6 +450,22 @@ <translation>Актуално</translation> </message> <message> + <source>Close Wallet...</source> + <translation>Затвори Портфейла</translation> + </message> + <message> + <source>Close wallet</source> + <translation>Затвори портфейла</translation> + </message> + <message> + <source>Close All Wallets...</source> + <translation>Затвори Всички Портфейли...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Затвори всички портфейли</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Покажи %1 помощно съобщение за да получиш лист с възможни Биткойн команди</translation> </message> @@ -454,6 +482,14 @@ <translation>Минимизирай</translation> </message> <message> + <source>Zoom</source> + <translation>Увеличи</translation> + </message> + <message> + <source>Main Window</source> + <translation>Главен Прозорец</translation> + </message> + <message> <source>%1 client</source> <translation>%1 клиент</translation> </message> @@ -511,11 +547,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Портфейлът е <b>криптиран</b> и <b>заключен</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Възникна фатална грешка. Биткойн не може да продължи безопасно и ще се изключи.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -1061,6 +1093,17 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>or</source> + <translation>или</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1231,10 +1274,6 @@ <translation>Брой връзки</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Текущ брой блокове</translation> - </message> - <message> <source>Received</source> <translation>Получени</translation> </message> @@ -1335,14 +1374,6 @@ <translation>Изходящи</translation> </message> <message> - <source>Yes</source> - <translation>Да</translation> - </message> - <message> - <source>No</source> - <translation>Не</translation> - </message> - <message> <source>Unknown</source> <translation>Неизвестен</translation> </message> @@ -1401,12 +1432,28 @@ <source>Copy amount</source> <translation>Копиране на сумата</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Не може да отключите портфейла.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR код</translation> + <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> <message> <source>Copy &URI</source> @@ -1428,26 +1475,6 @@ <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> </context> <context> <name>RecentRequestsTableModel</name> @@ -2188,12 +2215,20 @@ </context> <context> <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>Затвори портфейла</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Затвори всички портфейли</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Няма зареден портфейл.</translation> + <source>Create a new wallet</source> + <translation>Създай нов портфейл</translation> </message> </context> <context> @@ -2218,6 +2253,10 @@ <translation>Изнеси данните в избрания раздел към файл</translation> </message> <message> + <source>Error</source> + <translation>грешка</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Запазване на портфейла</translation> </message> diff --git a/src/qt/locale/bitcoin_bn.ts b/src/qt/locale/bitcoin_bn.ts index 3a68e2847c..10afa566b6 100644 --- a/src/qt/locale/bitcoin_bn.ts +++ b/src/qt/locale/bitcoin_bn.ts @@ -3,184 +3,3741 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>ঠিকানা কিংবা লেভেল সম্পাদনার জন্য রাইট-ক্লিক করুন</translation> + <translation>Right-click to edit address or label</translation> </message> <message> <source>Create a new address</source> - <translation>নতুন একটি ঠিকানা তৈরি করুন</translation> + <translation>Create a new address</translation> </message> <message> <source>&New</source> - <translation>নতুন</translation> + <translation>&New</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Copy the currently selected address to the system clipboard</translation> </message> <message> <source>&Copy</source> - <translation>কপি/প্রতিলিপি</translation> + <translation>&Copy</translation> </message> <message> <source>C&lose</source> - <translation>কপি/প্রতিলিপি</translation> + <translation>C&lose</translation> </message> - </context> + <message> + <source>Delete the currently selected address from the list</source> + <translation>Delete the currently selected address from the list</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>Enter address or label to search</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Export the data in the current tab to a file</translation> + </message> + <message> + <source>&Export</source> + <translation>&Export</translation> + </message> + <message> + <source>&Delete</source> + <translation>&Delete</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>Choose the address to send coins to</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>Choose the address to receive coins with</translation> + </message> + <message> + <source>C&hoose</source> + <translation>C&hoose</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Sending addresses</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Receiving addresses</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>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>&Copy Address</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 Address List</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Comma separated file (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Exporting Failed</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>There was an error trying to save the address list to %1. Please try again.</translation> + </message> +</context> <context> <name>AddressTableModel</name> <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> <source>Address</source> - <translation>ঠিকানা </translation> + <translation>Address</translation> </message> - </context> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> +</context> <context> <name>AskPassphraseDialog</name> - </context> + <message> + <source>Passphrase Dialog</source> + <translation>Passphrase Dialog</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>Enter passphrase</translation> + </message> + <message> + <source>New passphrase</source> + <translation>New passphrase</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Repeat new passphrase</translation> + </message> + <message> + <source>Show passphrase</source> + <translation>Show passphrase</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Encrypt wallet</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>This operation needs your wallet passphrase to unlock the wallet.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Unlock wallet</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>This operation needs your wallet passphrase to decrypt the wallet.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Decrypt wallet</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Change passphrase</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Confirm wallet encryption</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>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>Are you sure you wish to encrypt your wallet?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Wallet encrypted</translation> + </message> + <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Enter the old passphrase and new passphrase for the wallet.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Wallet to be encrypted</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Your wallet is about to be encrypted. </translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Your wallet is now encrypted. </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>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.</translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>Wallet encryption failed</translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>The supplied passphrases do not match.</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>Wallet unlock failed</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>The passphrase entered for the wallet decryption was incorrect.</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>Wallet decryption failed</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>Wallet passphrase was successfully changed.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>Warning: The Caps Lock key is on!</translation> + </message> +</context> <context> <name>BanTableModel</name> - </context> + <message> + <source>IP/Netmask</source> + <translation>IP/Netmask</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Banned Until</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> + <source>Sign &message...</source> + <translation>Sign &message...</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>Synchronizing with network...</translation> + </message> + <message> + <source>&Overview</source> + <translation>&Overview</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>Show general overview of wallet</translation> + </message> + <message> + <source>&Transactions</source> + <translation>&Transactions</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>Browse transaction history</translation> + </message> + <message> + <source>E&xit</source> + <translation>E&xit</translation> + </message> + <message> + <source>Quit application</source> + <translation>Quit application</translation> + </message> + <message> + <source>&About %1</source> + <translation>&About %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Show information about %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation>About &Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Show information about Qt</translation> + </message> + <message> + <source>&Options...</source> + <translation>&Options...</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation>Modify configuration options for %1</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>&Encrypt Wallet...</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>&Backup Wallet...</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>&Change Passphrase...</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>Open &URI...</translation> + </message> + <message> + <source>Create Wallet...</source> + <translation>Create Wallet...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Create a new wallet</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Wallet:</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>Click to disable network activity.</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Network activity disabled.</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>Click to enable network activity again.</translation> + </message> + <message> + <source>Syncing Headers (%1%)...</source> + <translation>Syncing Headers (%1%)...</translation> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <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> + <message> + <source>Backup wallet to another location</source> + <translation>Backup wallet to another location</translation> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation>Change the passphrase used for wallet encryption</translation> + </message> + <message> + <source>&Verify message...</source> + <translation>&Verify message...</translation> + </message> + <message> + <source>&Send</source> + <translation>&Send</translation> + </message> + <message> + <source>&Receive</source> + <translation>&Receive</translation> + </message> + <message> + <source>&Show / Hide</source> + <translation>&Show / Hide</translation> + </message> + <message> + <source>Show or hide the main Window</source> + <translation>Show or hide the main Window</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation>Encrypt the private keys that belong to your wallet</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation>Sign messages with your Bitcoin addresses to prove you own them</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> + </message> + <message> + <source>&File</source> + <translation>&File</translation> + </message> + <message> + <source>&Settings</source> + <translation>&Settings</translation> + </message> + <message> + <source>&Help</source> + <translation>&Help</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation>Tabs toolbar</translation> + </message> + <message> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation>Request payments (generates QR codes and bitcoin: URIs)</translation> + </message> + <message> + <source>Show the list of used sending addresses and labels</source> + <translation>Show the list of used sending addresses and labels</translation> + </message> + <message> + <source>Show the list of used receiving addresses and labels</source> + <translation>Show the list of used receiving addresses and labels</translation> + </message> + <message> + <source>&Command-line options</source> + <translation>&Command-line options</translation> + </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n active connection to Bitcoin network</numerusform><numerusform>%n active connections to Bitcoin network</numerusform></translation> + </message> + <message> + <source>Indexing blocks on disk...</source> + <translation>Indexing blocks on disk...</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Processing blocks on disk...</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Processed %n block of transaction history.</numerusform><numerusform>Processed %n blocks of transaction history.</numerusform></translation> + </message> + <message> + <source>%1 behind</source> + <translation>%1 behind</translation> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation>Last received block was generated %1 ago.</translation> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Transactions after this will not yet be visible.</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> <source>Warning</source> - <translation>সতর্কতা</translation> + <translation>Warning</translation> + </message> + <message> + <source>Information</source> + <translation>Information</translation> + </message> + <message> + <source>Up to date</source> + <translation>Up to date</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Open node debugging and diagnostic console</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation>&Sending addresses</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Receiving addresses</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation>Open a bitcoin: URI</translation> + </message> + <message> + <source>Open Wallet</source> + <translation>Open Wallet</translation> + </message> + <message> + <source>Open a wallet</source> + <translation>Open a wallet</translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>Close Wallet...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>Close wallet</translation> + </message> + <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Show the %1 help message to get a list with possible Bitcoin command-line options</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> + <message> + <source>No wallets available</source> + <translation>No wallets available</translation> + </message> + <message> + <source>&Window</source> + <translation>&Window</translation> + </message> + <message> + <source>Minimize</source> + <translation>Minimize</translation> + </message> + <message> + <source>Zoom</source> + <translation>Zoom</translation> + </message> + <message> + <source>Main Window</source> + <translation>Main Window</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 client</translation> + </message> + <message> + <source>Connecting to peers...</source> + <translation>Connecting to peers...</translation> + </message> + <message> + <source>Catching up...</source> + <translation>Catching up...</translation> + </message> + <message> + <source>Error: %1</source> + <translation>Error: %1</translation> + </message> + <message> + <source>Warning: %1</source> + <translation>Warning: %1</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>Date: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Amount: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>Wallet: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Type: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Label: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Address: %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation>Sent transaction</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>Incoming transaction</translation> + </message> + <message> + <source>HD key generation is <b>enabled</b></source> + <translation>HD key generation is <b>enabled</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>HD key generation is <b>disabled</b></translation> + </message> + <message> + <source>Private key <b>disabled</b></source> + <translation>Private key <b>disabled</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation>Wallet is <b>encrypted</b> and currently <b>unlocked</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> </context> <context> <name>CoinControlDialog</name> - </context> + <message> + <source>Coin Selection</source> + <translation>Coin Selection</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Quantity:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Amount:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Fee:</translation> + </message> + <message> + <source>Dust:</source> + <translation>Dust:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>After Fee:</translation> + </message> + <message> + <source>Change:</source> + <translation>Change:</translation> + </message> + <message> + <source>(un)select all</source> + <translation>(un)select all</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Tree mode</translation> + </message> + <message> + <source>List mode</source> + <translation>List mode</translation> + </message> + <message> + <source>Amount</source> + <translation>Amount</translation> + </message> + <message> + <source>Received with label</source> + <translation>Received with label</translation> + </message> + <message> + <source>Received with address</source> + <translation>Received with address</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Confirmations</source> + <translation>Confirmations</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Confirmed</translation> + </message> + <message> + <source>Copy address</source> + <translation>Copy address</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Copy transaction ID</translation> + </message> + <message> + <source>Lock unspent</source> + <translation>Lock unspent</translation> + </message> + <message> + <source>Unlock unspent</source> + <translation>Unlock unspent</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Copy quantity</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Copy fee</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Copy after fee</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Copy bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Copy dust</translation> + </message> + <message> + <source>Copy change</source> + <translation>Copy change</translation> + </message> + <message> + <source>(%1 locked)</source> + <translation>(%1 locked)</translation> + </message> + <message> + <source>yes</source> + <translation>yes</translation> + </message> + <message> + <source>no</source> + <translation>no</translation> + </message> + <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>This label turns red if any recipient receives an amount smaller than the current dust threshold.</translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Can vary +/- %1 satoshi(s) per input.</translation> + </message> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> + <message> + <source>change from %1 (%2)</source> + <translation>change from %1 (%2)</translation> + </message> + <message> + <source>(change)</source> + <translation>(change)</translation> + </message> +</context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Creating Wallet <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Create wallet failed</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Create wallet warning</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Create Wallet</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Wallet Name</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Encrypt Wallet</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Disable Private Keys</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Make Blank Wallet</translation> + </message> + <message> + <source>Create</source> + <translation>Create</translation> + </message> +</context> <context> <name>EditAddressDialog</name> - </context> + <message> + <source>Edit Address</source> + <translation>Edit Address</translation> + </message> + <message> + <source>&Label</source> + <translation>&Label</translation> + </message> + <message> + <source>The label associated with this address list entry</source> + <translation>The label associated with this address list entry</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>The address associated with this address list entry. This can only be modified for sending addresses.</translation> + </message> + <message> + <source>&Address</source> + <translation>&Address</translation> + </message> + <message> + <source>New sending address</source> + <translation>New sending address</translation> + </message> + <message> + <source>Edit receiving address</source> + <translation>Edit receiving address</translation> + </message> + <message> + <source>Edit sending address</source> + <translation>Edit sending address</translation> + </message> + <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <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> + <message> + <source>New key generation failed.</source> + <translation>New key generation failed.</translation> + </message> +</context> <context> <name>FreespaceChecker</name> - </context> + <message> + <source>A new data directory will be created.</source> + <translation>A new data directory will be created.</translation> + </message> + <message> + <source>name</source> + <translation>name</translation> + </message> + <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation>Directory already exists. Add %1 if you intend to create a new directory here.</translation> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation>Path already exists, and is not a directory.</translation> + </message> + <message> + <source>Cannot create data directory here.</source> + <translation>Cannot create data directory here.</translation> + </message> +</context> <context> <name>HelpMessageDialog</name> - </context> + <message> + <source>version</source> + <translation>version</translation> + </message> + <message> + <source>About %1</source> + <translation>About %1</translation> + </message> + <message> + <source>Command-line options</source> + <translation>Command-line options</translation> + </message> +</context> <context> <name>Intro</name> - </context> + <message> + <source>Welcome</source> + <translation>Welcome</translation> + </message> + <message> + <source>Welcome to %1.</source> + <translation>Welcome to %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>As this is the first time the program is launched, you can choose where %1 will store its data.</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>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.</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</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>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.</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>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> + </message> + <message> + <source>Use the default data directory</source> + <translation>Use the default data directory</translation> + </message> + <message> + <source>Use a custom data directory:</source> + <translation>Use a custom data directory:</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Discard blocks after verification, except most recent %1 GB (prune)</translation> + </message> + <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>At least %1 GB of data will be stored in this directory, and it will grow over time.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Approximately %1 GB of data will be stored in this directory.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 will download and store a copy of the Bitcoin block chain.</translation> + </message> + <message> + <source>The wallet will also be stored in this directory.</source> + <translation>The wallet will also be stored in this directory.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>Error: Specified data directory "%1" cannot be created.</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB of free space available</numerusform><numerusform>%n GB of free space available</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(of %n GB needed)</numerusform><numerusform>(of %n GB needed)</numerusform></translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB needed for full chain)</numerusform><numerusform>(%n GB needed for full chain)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> - </context> + <message> + <source>Form</source> + <translation>Form</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>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.</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>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</translation> + </message> + <message> + <source>Number of blocks left</source> + <translation>Number of blocks left</translation> + </message> + <message> + <source>Unknown...</source> + <translation>Unknown...</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>Progress</source> + <translation>Progress</translation> + </message> + <message> + <source>Progress increase per hour</source> + <translation>Progress increase per hour</translation> + </message> + <message> + <source>calculating...</source> + <translation>calculating...</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation>Estimated time left until synced</translation> + </message> + <message> + <source>Hide</source> + <translation>Hide</translation> + </message> + <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Unknown. Syncing Headers (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> - </context> + <message> + <source>Open bitcoin URI</source> + <translation>Open bitcoin URI</translation> + </message> + <message> + <source>URI:</source> + <translation>URI:</translation> + </message> +</context> <context> <name>OpenWalletActivity</name> - </context> + <message> + <source>Open wallet failed</source> + <translation>Open wallet failed</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Open wallet warning</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> + <message> + <source>Opening Wallet <b>%1</b>...</source> + <translation>Opening Wallet <b>%1</b>...</translation> + </message> +</context> <context> <name>OptionsDialog</name> - </context> + <message> + <source>Options</source> + <translation>Options</translation> + </message> + <message> + <source>&Main</source> + <translation>&Main</translation> + </message> + <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Automatically start %1 after logging in to the system.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Start %1 on system login</translation> + </message> + <message> + <source>Size of &database cache</source> + <translation>Size of &database cache</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation>Number of script &verification threads</translation> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>IP address of the proxy (e.g. 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>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</translation> + </message> + <message> + <source>Hide the icon from the system tray.</source> + <translation>Hide the icon from the system tray.</translation> + </message> + <message> + <source>&Hide tray icon</source> + <translation>&Hide tray icon</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>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.</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>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 |.</translation> + </message> + <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Open the %1 configuration file from the working directory.</translation> + </message> + <message> + <source>Open Configuration File</source> + <translation>Open Configuration File</translation> + </message> + <message> + <source>Reset all client options to default.</source> + <translation>Reset all client options to default.</translation> + </message> + <message> + <source>&Reset Options</source> + <translation>&Reset Options</translation> + </message> + <message> + <source>&Network</source> + <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>MiB</source> + <translation>MiB</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = auto, <0 = leave that many cores free)</translation> + </message> + <message> + <source>W&allet</source> + <translation>W&allet</translation> + </message> + <message> + <source>Expert</source> + <translation>Expert</translation> + </message> + <message> + <source>Enable coin &control features</source> + <translation>Enable coin &control features</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>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.</translation> + </message> + <message> + <source>&Spend unconfirmed change</source> + <translation>&Spend unconfirmed change</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>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <translation>Map port using &UPnP</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation>Accept connections from outside.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Allow incomin&g connections</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation>Connect to the Bitcoin network through a SOCKS5 proxy.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Connect through SOCKS5 proxy (default 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 of the proxy (e.g. 9050)</translation> + </message> + <message> + <source>Used for reaching peers via:</source> + <translation>Used for reaching peers via:</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>&Window</translation> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation>Show only a tray icon after minimizing the window.</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation>&Minimize to the tray instead of the taskbar</translation> + </message> + <message> + <source>M&inimize on close</source> + <translation>M&inimize on close</translation> + </message> + <message> + <source>&Display</source> + <translation>&Display</translation> + </message> + <message> + <source>User Interface &language:</source> + <translation>User Interface &language:</translation> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>The user interface language can be set here. This setting will take effect after restarting %1.</translation> + </message> + <message> + <source>&Unit to show amounts in:</source> + <translation>&Unit to show amounts in:</translation> + </message> + <message> + <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> + <translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation> + </message> + <message> + <source>Whether to show coin control features or not.</source> + <translation>Whether to show coin control features or not.</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>&Third party transaction URLs</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Options set in this dialog are overridden by the command line or in the configuration file:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancel</translation> + </message> + <message> + <source>default</source> + <translation>default</translation> + </message> + <message> + <source>none</source> + <translation>none</translation> + </message> + <message> + <source>Confirm options reset</source> + <translation>Confirm options reset</translation> + </message> + <message> + <source>Client restart required to activate changes.</source> + <translation>Client restart required to activate changes.</translation> + </message> + <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>Client will be shut down. Do you want to proceed?</translation> + </message> + <message> + <source>Configuration options</source> + <translation>Configuration options</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>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>The configuration file could not be opened.</source> + <translation>The configuration file could not be opened.</translation> + </message> + <message> + <source>This change would require a client restart.</source> + <translation>This change would require a client restart.</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation>The supplied proxy address is invalid.</translation> + </message> +</context> <context> <name>OverviewPage</name> + <message> + <source>Form</source> + <translation>Form</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>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.</translation> + </message> + <message> + <source>Watch-only:</source> + <translation>Watch-only:</translation> + </message> + <message> + <source>Available:</source> + <translation>Available:</translation> + </message> + <message> + <source>Your current spendable balance</source> + <translation>Your current spendable balance</translation> + </message> + <message> + <source>Pending:</source> + <translation>Pending:</translation> + </message> + <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> + </message> + <message> + <source>Immature:</source> + <translation>Immature:</translation> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation>Mined balance that has not yet matured</translation> + </message> + <message> + <source>Balances</source> + <translation>Balances</translation> + </message> + <message> + <source>Total:</source> + <translation>Total:</translation> + </message> + <message> + <source>Your current total balance</source> + <translation>Your current total balance</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>Your current balance in watch-only addresses</translation> + </message> + <message> + <source>Spendable:</source> + <translation>Spendable:</translation> + </message> + <message> + <source>Recent transactions</source> + <translation>Recent transactions</translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Unconfirmed transactions to watch-only addresses</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Mined balance in watch-only addresses that has not yet matured</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Current total balance in watch-only addresses</translation> + </message> </context> <context> - <name>PaymentServer</name> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> + </message> </context> <context> + <name>PaymentServer</name> + <message> + <source>Payment request error</source> + <translation>Payment request error</translation> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Cannot start bitcoin: click-to-pay handler</translation> + </message> + <message> + <source>URI handling</source> + <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>Cannot process payment request because BIP70 is not supported.</source> + <translation>Cannot process payment request because BIP70 is not supported.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</translation> + </message> + <message> + <source>Invalid payment address %1</source> + <translation>Invalid payment address %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 cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Payment request file handling</translation> + </message> +</context> +<context> <name>PeerTableModel</name> - </context> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node/Service</source> + <translation>Node/Service</translation> + </message> + <message> + <source>NodeId</source> + <translation>NodeId</translation> + </message> + <message> + <source>Ping</source> + <translation>Ping</translation> + </message> + <message> + <source>Sent</source> + <translation>Sent</translation> + </message> + <message> + <source>Received</source> + <translation>Received</translation> + </message> +</context> <context> <name>QObject</name> - </context> + <message> + <source>Amount</source> + <translation>Amount</translation> + </message> + <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Enter a Bitcoin address (e.g. %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>None</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 second</numerusform><numerusform>%n seconds</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>%n minute</numerusform><numerusform>%n minutes</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n hour</numerusform><numerusform>%n hours</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n day</numerusform><numerusform>%n days</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n week</numerusform><numerusform>%n weeks</numerusform></translation> + </message> + <message> + <source>%1 and %2</source> + <translation>%1 and %2</translation> + </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation><numerusform>%n year</numerusform><numerusform>%n years</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>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> + <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 didn't yet exit safely...</translation> + </message> + <message> + <source>unknown</source> + <translation>unknown</translation> + </message> +</context> <context> <name>QRImageWidget</name> - </context> + <message> + <source>&Save Image...</source> + <translation>&Save Image...</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&Copy Image</translation> + </message> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation>Resulting URI too long, try to reduce the text for label / message.</translation> + </message> + <message> + <source>Error encoding URI into QR Code.</source> + <translation>Error encoding URI into QR Code.</translation> + </message> + <message> + <source>QR code support not available.</source> + <translation>QR code support not available.</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>Save QR Code</translation> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>PNG Image (*.png)</translation> + </message> +</context> <context> <name>RPCConsole</name> - </context> + <message> + <source>N/A</source> + <translation>N/A</translation> + </message> + <message> + <source>Client version</source> + <translation>Client version</translation> + </message> + <message> + <source>&Information</source> + <translation>&Information</translation> + </message> + <message> + <source>General</source> + <translation>General</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Using BerkeleyDB version</translation> + </message> + <message> + <source>Datadir</source> + <translation>Datadir</translation> + </message> + <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>To specify a non-default location of the data directory use the '%1' option.</translation> + </message> + <message> + <source>Blocksdir</source> + <translation>Blocksdir</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>To specify a non-default location of the blocks directory use the '%1' option.</translation> + </message> + <message> + <source>Startup time</source> + <translation>Startup time</translation> + </message> + <message> + <source>Network</source> + <translation>Network</translation> + </message> + <message> + <source>Name</source> + <translation>Name</translation> + </message> + <message> + <source>Number of connections</source> + <translation>Number of connections</translation> + </message> + <message> + <source>Block chain</source> + <translation>Block chain</translation> + </message> + <message> + <source>Memory Pool</source> + <translation>Memory Pool</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation>Current number of transactions</translation> + </message> + <message> + <source>Memory usage</source> + <translation>Memory usage</translation> + </message> + <message> + <source>Wallet: </source> + <translation>Wallet: </translation> + </message> + <message> + <source>(none)</source> + <translation>(none)</translation> + </message> + <message> + <source>&Reset</source> + <translation>&Reset</translation> + </message> + <message> + <source>Received</source> + <translation>Received</translation> + </message> + <message> + <source>Sent</source> + <translation>Sent</translation> + </message> + <message> + <source>&Peers</source> + <translation>&Peers</translation> + </message> + <message> + <source>Banned peers</source> + <translation>Banned peers</translation> + </message> + <message> + <source>Select a peer to view detailed information.</source> + <translation>Select a peer to view detailed information.</translation> + </message> + <message> + <source>Direction</source> + <translation>Direction</translation> + </message> + <message> + <source>Version</source> + <translation>Version</translation> + </message> + <message> + <source>Starting Block</source> + <translation>Starting Block</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Synced Headers</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Synced Blocks</translation> + </message> + <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>The mapped Autonomous System used for diversifying peer selection.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapped AS</translation> + </message> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</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>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>Decrease font size</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Increase font size</translation> + </message> + <message> + <source>Services</source> + <translation>Services</translation> + </message> + <message> + <source>Connection Time</source> + <translation>Connection Time</translation> + </message> + <message> + <source>Last Send</source> + <translation>Last Send</translation> + </message> + <message> + <source>Last Receive</source> + <translation>Last Receive</translation> + </message> + <message> + <source>Ping Time</source> + <translation>Ping Time</translation> + </message> + <message> + <source>The duration of a currently outstanding ping.</source> + <translation>The duration of a currently outstanding ping.</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>Ping Wait</translation> + </message> + <message> + <source>Min Ping</source> + <translation>Min Ping</translation> + </message> + <message> + <source>Time Offset</source> + <translation>Time Offset</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>&Open</source> + <translation>&Open</translation> + </message> + <message> + <source>&Console</source> + <translation>&Console</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation>&Network Traffic</translation> + </message> + <message> + <source>Totals</source> + <translation>Totals</translation> + </message> + <message> + <source>In:</source> + <translation>In:</translation> + </message> + <message> + <source>Out:</source> + <translation>Out:</translation> + </message> + <message> + <source>Debug log file</source> + <translation>Debug log file</translation> + </message> + <message> + <source>Clear console</source> + <translation>Clear console</translation> + </message> + <message> + <source>1 &hour</source> + <translation>1 &hour</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &day</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &week</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &year</translation> + </message> + <message> + <source>&Disconnect</source> + <translation>&Disconnect</translation> + </message> + <message> + <source>Ban for</source> + <translation>Ban for</translation> + </message> + <message> + <source>&Unban</source> + <translation>&Unban</translation> + </message> + <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Welcome to the %1 RPC console.</translation> + </message> + <message> + <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> + <translation>Use up and down arrows to navigate history, and %1 to clear screen.</translation> + </message> + <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Type %1 for an overview of available commands.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>For more information on using this console type %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>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.</translation> + </message> + <message> + <source>Network activity disabled</source> + <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> + <message> + <source>via %1</source> + <translation>via %1</translation> + </message> + <message> + <source>never</source> + <translation>never</translation> + </message> + <message> + <source>Inbound</source> + <translation>Inbound</translation> + </message> + <message> + <source>Outbound</source> + <translation>Outbound</translation> + </message> + <message> + <source>Unknown</source> + <translation>Unknown</translation> + </message> +</context> <context> <name>ReceiveCoinsDialog</name> + <message> + <source>&Amount:</source> + <translation>&Amount:</translation> + </message> + <message> + <source>&Label:</source> + <translation>&Label:</translation> + </message> + <message> + <source>&Message:</source> + <translation>&Message:</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>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.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <translation>An optional label to associate with the new receiving address.</translation> + </message> + <message> + <source>Use this form to request payments. All fields are <b>optional</b>.</source> + <translation>Use this form to request payments. All fields are <b>optional</b>.</translation> + </message> + <message> + <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <translation>An optional amount to request. Leave this empty or zero to not request a specific amount.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>An optional message that is attached to the payment request and may be displayed to the sender.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Create new receiving address</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Clear all fields of the form.</translation> + </message> + <message> + <source>Clear</source> + <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> + <message> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation>Show the selected request (does the same as double clicking an entry)</translation> + </message> + <message> + <source>Show</source> + <translation>Show</translation> + </message> + <message> + <source>Remove the selected entries from the list</source> + <translation>Remove the selected entries from the list</translation> + </message> + <message> + <source>Remove</source> + <translation>Remove</translation> + </message> + <message> + <source>Copy URI</source> + <translation>Copy URI</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy message</source> + <translation>Copy message</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Could not unlock wallet.</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR কোড</translation> + <source>Amount:</source> + <translation>Amount:</translation> </message> <message> - <source>Address</source> - <translation>ঠিকানা </translation> + <source>Message:</source> + <translation>Message:</translation> </message> - </context> + <message> + <source>Wallet:</source> + <translation>Wallet:</translation> + </message> + <message> + <source>Copy &URI</source> + <translation>Copy &URI</translation> + </message> + <message> + <source>Copy &Address</source> + <translation>Copy &Address</translation> + </message> + <message> + <source>&Save Image...</source> + <translation>&Save Image...</translation> + </message> + <message> + <source>Request payment to %1</source> + <translation>Request payment to %1</translation> + </message> + <message> + <source>Payment information</source> + <translation>Payment information</translation> + </message> +</context> <context> <name>RecentRequestsTableModel</name> - </context> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>Message</source> + <translation>Message</translation> + </message> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> + <message> + <source>(no message)</source> + <translation>(no message)</translation> + </message> + <message> + <source>(no amount requested)</source> + <translation>(no amount requested)</translation> + </message> + <message> + <source>Requested</source> + <translation>Requested</translation> + </message> +</context> <context> <name>SendCoinsDialog</name> - </context> + <message> + <source>Send Coins</source> + <translation>Send Coins</translation> + </message> + <message> + <source>Coin Control Features</source> + <translation>Coin Control Features</translation> + </message> + <message> + <source>Inputs...</source> + <translation>Inputs...</translation> + </message> + <message> + <source>automatically selected</source> + <translation>automatically selected</translation> + </message> + <message> + <source>Insufficient funds!</source> + <translation>Insufficient funds!</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Quantity:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Amount:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Fee:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>After Fee:</translation> + </message> + <message> + <source>Change:</source> + <translation>Change:</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>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</translation> + </message> + <message> + <source>Custom change address</source> + <translation>Custom change address</translation> + </message> + <message> + <source>Transaction Fee:</source> + <translation>Transaction Fee:</translation> + </message> + <message> + <source>Choose...</source> + <translation>Choose...</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>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.</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>Warning: Fee estimation is currently not possible.</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> + <message> + <source>Hide</source> + <translation>Hide</translation> + </message> + <message> + <source>Recommended:</source> + <translation>Recommended:</translation> + </message> + <message> + <source>Custom:</source> + <translation>Custom:</translation> + </message> + <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(Smart fee not initialized yet. This usually takes a few blocks...)</translation> + </message> + <message> + <source>Send to multiple recipients at once</source> + <translation>Send to multiple recipients at once</translation> + </message> + <message> + <source>Add &Recipient</source> + <translation>Add &Recipient</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Clear all fields of the form.</translation> + </message> + <message> + <source>Dust:</source> + <translation>Dust:</translation> + </message> + <message> + <source>Hide transaction fee settings</source> + <translation>Hide transaction fee settings</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>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.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>A too low fee might result in a never confirming transaction (read the tooltip)</translation> + </message> + <message> + <source>Confirmation time target:</source> + <translation>Confirmation time target:</translation> + </message> + <message> + <source>Enable Replace-By-Fee</source> + <translation>Enable 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>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.</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> + <source>Balance:</source> + <translation>Balance:</translation> + </message> + <message> + <source>Confirm the send action</source> + <translation>Confirm the send action</translation> + </message> + <message> + <source>S&end</source> + <translation>S&end</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Copy quantity</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Copy fee</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Copy after fee</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Copy bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Copy dust</translation> + </message> + <message> + <source>Copy change</source> + <translation>Copy change</translation> + </message> + <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 blocks)</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation>Cr&eate Unsigned</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation> from wallet '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 to '%2'</translation> + </message> + <message> + <source>%1 to %2</source> + <translation>%1 to %2</translation> + </message> + <message> + <source>Do you want to draft this transaction?</source> + <translation>Do you want to draft this transaction?</translation> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation>Are you sure you want to send?</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> + </message> + <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</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> + <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Not signalling Replace-By-Fee, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>To review recipient list click "Show Details..."</source> + <translation>To review recipient list click "Show Details..."</translation> + </message> + <message> + <source>Confirm send coins</source> + <translation>Confirm send coins</translation> + </message> + <message> + <source>Confirm transaction proposal</source> + <translation>Confirm transaction proposal</translation> + </message> + <message> + <source>Send</source> + <translation>Send</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Watch-only balance:</translation> + </message> + <message> + <source>The recipient address is not valid. Please recheck.</source> + <translation>The recipient address is not valid. Please recheck.</translation> + </message> + <message> + <source>The amount to pay must be larger than 0.</source> + <translation>The amount to pay must be larger than 0.</translation> + </message> + <message> + <source>The amount exceeds your balance.</source> + <translation>The amount exceeds your balance.</translation> + </message> + <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation>The total exceeds your balance when the %1 transaction fee is included.</translation> + </message> + <message> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation>Duplicate address found: addresses should only be used once each.</translation> + </message> + <message> + <source>Transaction creation failed!</source> + <translation>Transaction creation failed!</translation> + </message> + <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>A fee higher than %1 is considered an absurdly high fee.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Payment request expired.</translation> + </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Estimated to begin confirmation within %n block.</numerusform><numerusform>Estimated to begin confirmation within %n blocks.</numerusform></translation> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Warning: Invalid Bitcoin address</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>Warning: Unknown change address</translation> + </message> + <message> + <source>Confirm custom change address</source> + <translation>Confirm custom change address</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>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?</translation> + </message> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> +</context> <context> <name>SendCoinsEntry</name> - </context> + <message> + <source>A&mount:</source> + <translation>A&mount:</translation> + </message> + <message> + <source>Pay &To:</source> + <translation>Pay &To:</translation> + </message> + <message> + <source>&Label:</source> + <translation>&Label:</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Choose previously used address</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>The Bitcoin address to send the payment to</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Remove this entry</source> + <translation>Remove this entry</translation> + </message> + <message> + <source>The amount to send in the selected unit</source> + <translation>The amount to send in the selected unit</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>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.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation>S&ubtract fee from amount</translation> + </message> + <message> + <source>Use available balance</source> + <translation>Use available balance</translation> + </message> + <message> + <source>Message:</source> + <translation>Message:</translation> + </message> + <message> + <source>This is an unauthenticated payment request.</source> + <translation>This is an unauthenticated payment request.</translation> + </message> + <message> + <source>This is an authenticated payment request.</source> + <translation>This is an authenticated payment request.</translation> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation>Enter a label for this address to add it to the list of used addresses</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>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.</translation> + </message> + <message> + <source>Pay To:</source> + <translation>Pay To:</translation> + </message> + <message> + <source>Memo:</source> + <translation>Memo:</translation> + </message> +</context> <context> <name>ShutdownWindow</name> - </context> + <message> + <source>%1 is shutting down...</source> + <translation>%1 is shutting down...</translation> + </message> + <message> + <source>Do not shut down the computer until this window disappears.</source> + <translation>Do not shut down the computer until this window disappears.</translation> + </message> +</context> <context> <name>SignVerifyMessageDialog</name> <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Signatures - Sign / Verify a Message</translation> + </message> + <message> + <source>&Sign Message</source> + <translation>&Sign Message</translation> + </message> + <message> + <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <translation>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.</translation> + </message> + <message> + <source>The Bitcoin address to sign the message with</source> + <translation>The Bitcoin address to sign the message with</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Choose previously used address</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Enter the message you want to sign here</source> + <translation>Enter the message you want to sign here</translation> + </message> + <message> + <source>Signature</source> + <translation>Signature</translation> + </message> + <message> + <source>Copy the current signature to the system clipboard</source> + <translation>Copy the current signature to the system clipboard</translation> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation>Sign the message to prove you own this Bitcoin address</translation> + </message> + <message> + <source>Sign &Message</source> + <translation>Sign &Message</translation> + </message> + <message> + <source>Reset all sign message fields</source> + <translation>Reset all sign message fields</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> + <source>&Verify Message</source> + <translation>&Verify Message</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>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!</translation> + </message> + <message> + <source>The Bitcoin address the message was signed with</source> + <translation>The Bitcoin address the message was signed with</translation> + </message> + <message> + <source>The signed message to verify</source> + <translation>The signed message to verify</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>The signature given when the message was signed</translation> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation>Verify the message to ensure it was signed with the specified Bitcoin address</translation> + </message> + <message> + <source>Verify &Message</source> + <translation>Verify &Message</translation> + </message> + <message> + <source>Reset all verify message fields</source> + <translation>Reset all verify message fields</translation> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation>Click "Sign Message" to generate signature</translation> + </message> + <message> <source>The entered address is invalid.</source> - <translation>প্রবেশকৃত ঠিকানাটি শুদ্ধ নয়।</translation> + <translation>The entered address is invalid.</translation> + </message> + <message> + <source>Please check the address and try again.</source> + <translation>Please check the address and try again.</translation> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation>The entered address does not refer to a key.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation>Wallet unlock was cancelled.</translation> + </message> + <message> + <source>No error</source> + <translation>No error</translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation>Private key for the entered address is not available.</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Message signing failed.</translation> + </message> + <message> + <source>Message signed.</source> + <translation>Message signed.</translation> + </message> + <message> + <source>The signature could not be decoded.</source> + <translation>The signature could not be decoded.</translation> </message> <message> <source>Please check the signature and try again.</source> - <translation>অনুগ্রহ করে স্বাক্ষরটি পুনরায় পরীক্ষা করে আবারও চেষ্টা করুন।</translation> + <translation>Please check the signature and try again.</translation> </message> - </context> + <message> + <source>The signature did not match the message digest.</source> + <translation>The signature did not match the message digest.</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>Message verification failed.</translation> + </message> + <message> + <source>Message verified.</source> + <translation>Message verified.</translation> + </message> +</context> <context> <name>TrafficGraphWidget</name> - </context> + <message> + <source>KB/s</source> + <translation>KB/s</translation> + </message> +</context> <context> <name>TransactionDesc</name> - </context> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> + <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>conflicted with a transaction with %1 confirmations</source> + <translation>conflicted with a transaction with %1 confirmations</translation> + </message> + <message> + <source>0/unconfirmed, %1</source> + <translation>0/unconfirmed, %1</translation> + </message> + <message> + <source>in memory pool</source> + <translation>in memory pool</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>not in memory pool</translation> + </message> + <message> + <source>abandoned</source> + <translation>abandoned</translation> + </message> + <message> + <source>%1/unconfirmed</source> + <translation>%1/unconfirmed</translation> + </message> + <message> + <source>%1 confirmations</source> + <translation>%1 confirmations</translation> + </message> + <message> + <source>Status</source> + <translation>Status</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Source</source> + <translation>Source</translation> + </message> + <message> + <source>Generated</source> + <translation>Generated</translation> + </message> + <message> + <source>From</source> + <translation>From</translation> + </message> + <message> + <source>unknown</source> + <translation>unknown</translation> + </message> + <message> + <source>To</source> + <translation>To</translation> + </message> + <message> + <source>own address</source> + <translation>own address</translation> + </message> + <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> + <source>label</source> + <translation>label</translation> + </message> + <message> + <source>Credit</source> + <translation>Credit</translation> + </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>matures in %n more block</numerusform><numerusform>matures in %n more blocks</numerusform></translation> + </message> + <message> + <source>not accepted</source> + <translation>not accepted</translation> + </message> + <message> + <source>Debit</source> + <translation>Debit</translation> + </message> + <message> + <source>Total debit</source> + <translation>Total debit</translation> + </message> + <message> + <source>Total credit</source> + <translation>Total credit</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>Transaction fee</translation> + </message> + <message> + <source>Net amount</source> + <translation>Net amount</translation> + </message> + <message> + <source>Message</source> + <translation>Message</translation> + </message> + <message> + <source>Comment</source> + <translation>Comment</translation> + </message> + <message> + <source>Transaction ID</source> + <translation>Transaction ID</translation> + </message> + <message> + <source>Transaction total size</source> + <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> + <message> + <source> (Certificate was not verified)</source> + <translation> (Certificate was not verified)</translation> + </message> + <message> + <source>Merchant</source> + <translation>Merchant</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>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.</translation> + </message> + <message> + <source>Debug information</source> + <translation>Debug information</translation> + </message> + <message> + <source>Transaction</source> + <translation>Transaction</translation> + </message> + <message> + <source>Inputs</source> + <translation>Inputs</translation> + </message> + <message> + <source>Amount</source> + <translation>Amount</translation> + </message> + <message> + <source>true</source> + <translation>true</translation> + </message> + <message> + <source>false</source> + <translation>false</translation> + </message> +</context> <context> <name>TransactionDescDialog</name> - </context> + <message> + <source>This pane shows a detailed description of the transaction</source> + <translation>This pane shows a detailed description of the transaction</translation> + </message> + <message> + <source>Details for %1</source> + <translation>Details for %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> - </context> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Type</source> + <translation>Type</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> + <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>Unconfirmed</source> + <translation>Unconfirmed</translation> + </message> + <message> + <source>Abandoned</source> + <translation>Abandoned</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation>Confirming (%1 of %2 recommended confirmations)</translation> + </message> + <message> + <source>Confirmed (%1 confirmations)</source> + <translation>Confirmed (%1 confirmations)</translation> + </message> + <message> + <source>Conflicted</source> + <translation>Conflicted</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation>Immature (%1 confirmations, will be available after %2)</translation> + </message> + <message> + <source>Generated but not accepted</source> + <translation>Generated but not accepted</translation> + </message> + <message> + <source>Received with</source> + <translation>Received with</translation> + </message> + <message> + <source>Received from</source> + <translation>Received from</translation> + </message> + <message> + <source>Sent to</source> + <translation>Sent to</translation> + </message> + <message> + <source>Payment to yourself</source> + <translation>Payment to yourself</translation> + </message> + <message> + <source>Mined</source> + <translation>Mined</translation> + </message> + <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> + <source>(n/a)</source> + <translation>(n/a)</translation> + </message> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> + <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation>Transaction status. Hover over this field to show number of confirmations.</translation> + </message> + <message> + <source>Date and time that the transaction was received.</source> + <translation>Date and time that the transaction was received.</translation> + </message> + <message> + <source>Type of transaction.</source> + <translation>Type of transaction.</translation> + </message> + <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Whether or not a watch-only address is involved in this transaction.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>User-defined intent/purpose of the transaction.</translation> + </message> + <message> + <source>Amount removed from or added to balance.</source> + <translation>Amount removed from or added to balance.</translation> + </message> +</context> <context> <name>TransactionView</name> <message> + <source>All</source> + <translation>All</translation> + </message> + <message> + <source>Today</source> + <translation>Today</translation> + </message> + <message> + <source>This week</source> + <translation>This week</translation> + </message> + <message> + <source>This month</source> + <translation>This month</translation> + </message> + <message> + <source>Last month</source> + <translation>Last month</translation> + </message> + <message> + <source>This year</source> + <translation>This year</translation> + </message> + <message> + <source>Range...</source> + <translation>Range...</translation> + </message> + <message> + <source>Received with</source> + <translation>Received with</translation> + </message> + <message> + <source>Sent to</source> + <translation>Sent to</translation> + </message> + <message> + <source>To yourself</source> + <translation>To yourself</translation> + </message> + <message> + <source>Mined</source> + <translation>Mined</translation> + </message> + <message> + <source>Other</source> + <translation>Other</translation> + </message> + <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Enter address, transaction id, or label to search</translation> + </message> + <message> + <source>Min amount</source> + <translation>Min amount</translation> + </message> + <message> + <source>Abandon transaction</source> + <translation>Abandon transaction</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>Increase transaction fee</translation> + </message> + <message> + <source>Copy address</source> + <translation>Copy address</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Copy transaction ID</translation> + </message> + <message> + <source>Copy raw transaction</source> + <translation>Copy raw transaction</translation> + </message> + <message> + <source>Copy full transaction details</source> + <translation>Copy full transaction details</translation> + </message> + <message> + <source>Edit label</source> + <translation>Edit label</translation> + </message> + <message> + <source>Show transaction details</source> + <translation>Show transaction details</translation> + </message> + <message> + <source>Export Transaction History</source> + <translation>Export Transaction History</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Comma separated file (*.csv)</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Confirmed</translation> + </message> + <message> + <source>Watch-only</source> + <translation>Watch-only</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Type</source> + <translation>Type</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> <source>Address</source> - <translation>ঠিকানা </translation> + <translation>Address</translation> </message> - </context> + <message> + <source>ID</source> + <translation>ID</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Exporting Failed</translation> + </message> + <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation>There was an error trying to save the transaction history to %1.</translation> + </message> + <message> + <source>Exporting Successful</source> + <translation>Exporting Successful</translation> + </message> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>The transaction history was successfully saved to %1.</translation> + </message> + <message> + <source>Range:</source> + <translation>Range:</translation> + </message> + <message> + <source>to</source> + <translation>to</translation> + </message> +</context> <context> <name>UnitDisplayStatusBarControl</name> - </context> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Unit to show amounts in. Click to select another unit.</translation> + </message> +</context> <context> <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>Close wallet</translation> + </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Are you sure you wish to close the wallet <i>%1</i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</translation> + </message> </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Create a new wallet</translation> + </message> +</context> <context> <name>WalletModel</name> - </context> + <message> + <source>Send Coins</source> + <translation>Send Coins</translation> + </message> + <message> + <source>Fee bump error</source> + <translation>Fee bump error</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation>Increasing transaction fee failed</translation> + </message> + <message> + <source>Do you want to increase the fee?</source> + <translation>Do you want to increase the fee?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Do you want to draft a transaction with fee increase?</translation> + </message> + <message> + <source>Current fee:</source> + <translation>Current fee:</translation> + </message> + <message> + <source>Increase:</source> + <translation>Increase:</translation> + </message> + <message> + <source>New fee:</source> + <translation>New fee:</translation> + </message> + <message> + <source>Confirm fee bump</source> + <translation>Confirm fee bump</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Can't draft transaction.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT copied</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Can't sign transaction.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Could not commit transaction</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> +</context> <context> <name>WalletView</name> - </context> + <message> + <source>&Export</source> + <translation>&Export</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Export the data in the current tab to a file</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>Backup Wallet</translation> + </message> + <message> + <source>Wallet Data (*.dat)</source> + <translation>Wallet Data (*.dat)</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>Backup Failed</translation> + </message> + <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation>There was an error trying to save the wallet data to %1.</translation> + </message> + <message> + <source>Backup Successful</source> + <translation>Backup Successful</translation> + </message> + <message> + <source>The wallet data was successfully saved to %1.</source> + <translation>The wallet data was successfully saved to %1.</translation> + </message> + <message> + <source>Cancel</source> + <translation>Cancel</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>Distributed under the MIT software license, see the accompanying file %s or %s</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Prune configured below the minimum of %d MiB. Please use a higher number.</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>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Pruning blockstore...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Unable to start HTTP server. See debug log for details.</translation> + </message> + <message> + <source>The %s developers</source> + <translation>The %s developers</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Cannot obtain a lock on data directory %s. %s is probably already running.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Cannot provide specific connections and have addrman find outgoing connections at the same.</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>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</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> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Please contribute if you find %s useful. Visit %s for further information about the software.</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>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</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>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation> + </message> + <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>This is the transaction fee you may discard if change is smaller than dust at this level</translation> + </message> + <message> + <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <translation>Unable to replay blocks. You will need to rebuild the database using -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>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</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>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation> + </message> + <message> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool must be at least %d MB</translation> + </message> + <message> + <source>Cannot resolve -%s address: '%s'</source> + <translation>Cannot resolve -%s address: '%s'</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>Change index out of range</translation> + </message> + <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Config setting for %s only applied on %s network when in [%s] section.</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation>Corrupted block database detected</translation> + </message> + <message> + <source>Could not find asmap file %s</source> + <translation>Could not find asmap file %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Could not parse asmap file %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> - <translation>আপনি কি পুনরায় ব্লক ডাটাবেইজ এখনই তৈরি করতে চান?</translation> + <translation>Do you want to rebuild the block database now?</translation> + </message> + <message> + <source>Error initializing block database</source> + <translation>Error initializing block database</translation> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation>Error initializing wallet database environment %s!</translation> + </message> + <message> + <source>Error loading %s</source> + <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> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Error loading %s: Wallet requires newer version of %s</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>Error loading block database</translation> + </message> + <message> + <source>Error opening block database</source> + <translation>Error opening block database</translation> + </message> + <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> + </message> + <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Failed to rescan the wallet during initialization</translation> + </message> + <message> + <source>Importing...</source> + <translation>Importing...</translation> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>Initialization sanity check failed. %s is shutting down.</translation> + </message> + <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Invalid P2P permission: '%s'</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Invalid amount for -%s=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -discardfee=<amount>: '%s'</source> + <translation>Invalid amount for -discardfee=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> + <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>Unknown address type '%s'</source> + <translation>Unknown address type '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Unknown change type '%s'</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> + <message> + <source>Loading banlist...</source> + <translation>Loading banlist...</translation> + </message> + <message> + <source>Not enough file descriptors available.</source> + <translation>Not enough file descriptors available.</translation> + </message> + <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Prune cannot be configured with a negative value.</translation> + </message> + <message> + <source>Prune mode is incompatible with -txindex.</source> + <translation>Prune mode is incompatible with -txindex.</translation> + </message> + <message> + <source>Replaying blocks...</source> + <translation>Replaying blocks...</translation> + </message> + <message> + <source>Rewinding blocks...</source> + <translation>Rewinding blocks...</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>The source code is available from %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <translation>Transaction fee and change calculation failed</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <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 logging category %s=%s.</source> + <translation>Unsupported logging category %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Upgrading UTXO database</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>User Agent comment (%s) contains unsafe characters.</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>Verifying blocks...</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Wallet needed to be rewritten: restart %s to complete</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Error: Listening for incoming connections failed (listen returned error %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>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>The transaction amount is too small to send after the fee has been deducted</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>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Error reading from database, shutting down.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Error upgrading chainstate database</translation> + </message> + <message> + <source>Error: Disk space is low for %s</source> + <translation>Error: Disk space is low for %s</translation> + </message> + <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Invalid -onion address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Invalid -proxy address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Invalid netmask specified in -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Need to specify a port with -whitebind: '%s'</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Prune mode is incompatible with -blockfilterindex.</translation> + </message> + <message> + <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> + <translation>Reducing -maxconnections from %d to %d, because of system limitations.</translation> + </message> + <message> + <source>Section [%s] is not recognized.</source> + <translation>Section [%s] is not recognized.</translation> + </message> + <message> + <source>Signing transaction failed</source> + <translation>Signing transaction failed</translation> + </message> + <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Specified -walletdir "%s" does not exist</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Specified -walletdir "%s" is a relative path</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Specified -walletdir "%s" is not a directory</translation> + </message> + <message> + <source>The specified config file %s does not exist +</source> + <translation>The specified config file %s does not exist +</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>The transaction amount is too small to pay the fee</translation> </message> <message> <source>This is experimental software.</source> - <translation>এটি পরীক্ষামূলক সফটওয়্যার।</translation> + <translation>This is experimental software.</translation> </message> <message> <source>Transaction amount too small</source> - <translation>লেনদেনের পরিমান অনেক ছোট</translation> + <translation>Transaction amount too small</translation> </message> <message> <source>Transaction too large</source> - <translation>লেনদেনর অংক অনেক বড়</translation> + <translation>Transaction too large</translation> </message> - </context> + <message> + <source>Unable to bind to %s on this computer (bind returned error %s)</source> + <translation>Unable to bind to %s on this computer (bind returned error %s)</translation> + </message> + <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>Unable to create the PID file '%s': %s</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>Unable to generate initial keys</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Unknown -blockfilterindex value %s.</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>Verifying wallet(s)...</translation> + </message> + <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Warning: unknown new rules activated (versionbit %i)</translation> + </message> + <message> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation> + </message> + <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>This is the transaction fee you may pay when fee estimates are not available.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s is set very high!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Error loading wallet %s. Duplicate -wallet filename specified.</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>Starting network threads...</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>The wallet will avoid paying less than the minimum relay fee.</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>This is the minimum transaction fee you pay on every transaction.</translation> + </message> + <message> + <source>This is the transaction fee you will pay if you send a transaction.</source> + <translation>This is the transaction fee you will pay if you send a transaction.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <translation>Transaction amounts must not be negative</translation> + </message> + <message> + <source>Transaction has too long of a mempool chain</source> + <translation>Transaction has too long of a mempool chain</translation> + </message> + <message> + <source>Transaction must have at least one recipient</source> + <translation>Transaction must have at least one recipient</translation> + </message> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation>Unknown network specified in -onlynet: '%s'</translation> + </message> + <message> + <source>Insufficient funds</source> + <translation>Insufficient funds</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> + <message> + <source>Loading wallet...</source> + <translation>Loading wallet...</translation> + </message> + <message> + <source>Cannot downgrade wallet</source> + <translation>Cannot downgrade wallet</translation> + </message> + <message> + <source>Rescanning...</source> + <translation>Rescanning...</translation> + </message> + <message> + <source>Done loading</source> + <translation>Done loading</translation> + </message> +</context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_bs.ts b/src/qt/locale/bitcoin_bs.ts index ef97da747a..be76c6c418 100644 --- a/src/qt/locale/bitcoin_bs.ts +++ b/src/qt/locale/bitcoin_bs.ts @@ -151,6 +151,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index e14fc3097e..4faab2e7fb 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Feu clic dret per a editar l'adreça o l'etiqueta</translation> + <translation>Feu clic al botó dret per a editar l'adreça o l'etiqueta</translation> </message> <message> <source>Create a new address</source> @@ -23,7 +23,7 @@ </message> <message> <source>C&lose</source> - <translation>&Tanca</translation> + <translation>T&anca</translation> </message> <message> <source>Delete the currently selected address from the list</source> @@ -70,6 +70,12 @@ <translation>Aquestes són les vostres adreces de Bitcoin per enviar els pagaments. Sempre reviseu l'import i l'adreça del destinatari abans de transferir monedes.</translation> </message> <message> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Aquestes son les teves adreces de Bitcoin per rebre pagaments. Utilitza el botó "Crear nova adreça de recepció" de la pestanya de recepció per crear una nova adreça. +Només és possible firmar amb adreces del tipus "legacy".</translation> + </message> + <message> <source>&Copy Address</source> <translation>&Copia l'adreça</translation> </message> @@ -184,6 +190,10 @@ <translation>Introduïu la contrasenya antiga i la contrasenya nova a la cartera.</translation> </message> <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Recorda que tot i xifrant la teva cartera, els teus bitcoins no estan completament protegits de robatori a través de programari maliciós que estigui infectant el teu ordinador.</translation> + </message> + <message> <source>Wallet to be encrypted</source> <translation>Cartera per ser encriptada</translation> </message> @@ -283,7 +293,7 @@ </message> <message> <source>Show information about %1</source> - <translation>Mosta informació sobre el %1</translation> + <translation>Mostra informació sobre el %1</translation> </message> <message> <source>About &Qt</source> @@ -318,6 +328,14 @@ <translation>Obre un &URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Crear Cartera...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crear una nova cartera</translation> + </message> + <message> <source>Wallet:</source> <translation>Moneder:</translation> </message> @@ -421,6 +439,10 @@ <source>&Command-line options</source> <translation>Opcions de la &línia d'ordres</translation> </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>Una connexió activa a la xarxa de Bitcoin</numerusform><numerusform>%n connexions actives a la xarxa de Bitcoin</numerusform></translation> + </message> <message> <source>Indexing blocks on disk...</source> <translation>S'estan indexant els blocs al disc...</translation> @@ -429,6 +451,10 @@ <source>Processing blocks on disk...</source> <translation>S'estan processant els blocs al disc...</translation> </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Processat un bloc de l'historial de transaccions.</numerusform><numerusform>Processat %n blocs de l'historial de transaccions.</numerusform></translation> + </message> <message> <source>%1 behind</source> <translation>%1 darrere</translation> @@ -458,6 +484,30 @@ <translation>Actualitzat</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Carrega el PSBT des del fitxer ...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Carrega la transacció Bitcoin signada parcialment</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Carrega PSBT des del porta-retalls ...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Carrega la transacció de Bitcoin signada parcialment des del porta-retalls</translation> + </message> + <message> + <source>Node window</source> + <translation>Finestra node</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Obrir depurador de node i consola de diagnosi.</translation> + </message> + <message> <source>&Sending addresses</source> <translation>Adreces d'&enviament</translation> </message> @@ -466,12 +516,16 @@ <translation>Adreces de &recepció</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Obrir un bitcoin: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Obre la cartera</translation> </message> <message> <source>Open a wallet</source> - <translation>Obre la cartera</translation> + <translation>Obre una cartera</translation> </message> <message> <source>Close Wallet...</source> @@ -482,10 +536,26 @@ <translation>Tanca la cartera</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Tanca totes les carteres ...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Tanqueu totes les carteres</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Mostra el missatge d'ajuda del %1 per obtenir una llista amb les possibles opcions de línia d'ordres de Bitcoin</translation> </message> <message> + <source>&Mask values</source> + <translation>&Emmascara els valors</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Emmascara els valors en la pestanya Visió general</translation> + </message> + <message> <source>default wallet</source> <translation>cartera predeterminada</translation> </message> @@ -526,6 +596,10 @@ <translation>Avís: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>Avís: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>Data: %1 @@ -590,8 +664,12 @@ <translation>La cartera està <b>encriptada</b> i actualment <b>blocada</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>S'ha produït un error fatal. Bitcoin no pot continuar amb seguretat i finalitzarà.</translation> + <source>Original message:</source> + <translation>Missatge original:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>S'ha produït un error fatal. %1 ja no pot continuar amb seguretat i sortirà.</translation> </message> </context> <context> @@ -747,10 +825,67 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Creant cartera <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>La creació de cartera ha fallat</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Avís en la creació de la cartera</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Crear cartera</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Nom de la cartera</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Xifra la cartera. La cartera serà xifrada amb la contrasenya que escullis.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Xifrar la cartera</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Deshabilita les claus privades per a aquesta cartera. Carteres amb claus privades deshabilitades no tindran cap clau privada i no podran tenir cap llavor HD o importar claus privades. +Això és ideal per a carteres de mode només lectura.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Deshabilitar claus privades</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Crea una cartera en blanc. Carteres en blanc no tenen claus privades inicialment o scripts. Claus privades i adreces poden ser importades, o una llavor HD, més endavant.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Fes cartera en blanc</translation> + </message> + <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Utilitzeu descriptors per a la gestió de scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Cartera del descriptor</translation> + </message> + <message> + <source>Create</source> + <translation>Crear</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -856,13 +991,17 @@ </message> <message> <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> - <translation>Com és la primera vegada que s'executa el programa, podeu triar on %1 emmagatzemarà les dades.</translation> + <translation>Com és la primera vegada que s'executa el programa, podeu triar on %1 emmagatzemaran les dades.</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>Quan feu clic a D'acord, %1 començarà a descarregar i processar la cadena de blocs %4 completa (%2 GB) començant per les primeres transaccions de %3, any de llençament inicial de %4.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Desfer aquest canvi requereix tornar-se a descarregar el blockchain sencer. És més ràpid descarregar la cadena completa primer i després podar. Deshabilita algunes de les característiques avançades.</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>Aquesta sincronització inicial és molt exigent i pot exposar problemes de maquinari amb l'equip que anteriorment havien passat desapercebuts. Cada vegada que executeu %1, continuarà descarregant des del punt on es va deixar.</translation> </message> @@ -883,6 +1022,10 @@ <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Descarta blocs després de la verificació, excepte el més recent %1 GB (podar)</translation> + </message> + <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <translation>Almenys %1 GB de dades s'emmagatzemaran en aquest directori, i creixerà amb el temps.</translation> </message> @@ -906,7 +1049,19 @@ <source>Error</source> <translation>Error</translation> </message> - </context> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>Un GB d'espai lliure disponible.</numerusform><numerusform>%n GB d'espai lliure disponibles</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(Un GB necessari)</numerusform><numerusform>(de %n GB necessàris)</numerusform></translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(Un GB necessari per a la cadena completa)</numerusform><numerusform>(Un GB necessari per a la cadena completa)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -954,6 +1109,14 @@ <translation>Amaga</translation> </message> <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 sincronitzant ara mateix. Es descarregaran capçaleres i blocs d'altres peers i es validaran fins a obtenir la punta de la cadena de blocs. </translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Desconegut. Sincronització de les capçaleres (%1, %2%)...</translation> </message> @@ -961,6 +1124,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Obre Bitcoin URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -968,6 +1135,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Ha fallat l'obertura de la cartera</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Avís en l'obertura de la cartera</translation> + </message> + <message> <source>default wallet</source> <translation>moneder per defecte</translation> </message> @@ -1011,10 +1186,6 @@ <translation>Mostra si el proxy SOCKS5 predeterminat subministrat s'utilitza per arribar a altres nodes a través d'aquest tipus de xarxa.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Usi un proxy SOCKS&5 separat per connectar amb nodes a través dels serveis ocults de Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Amaga la icona de la safata del sistema</translation> </message> @@ -1147,10 +1318,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Conectar a la red de Bitcoin a través de un proxy SOCKS5 per als serveis ocults de Tor</translation> - </message> - <message> <source>&Window</source> <translation>&Finestra</translation> </message> @@ -1191,10 +1358,22 @@ <translation>Si voleu mostrar les funcions de control de monedes o no.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Connecteu-vos a la xarxa Bitcoin mitjançant un servidor intermediari SOCKS5 separat per als serveis de ceba Tor.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Utilitzeu el servidor intermediari SOCKS&5 per arribar als peers mitjançant els serveis d'onion de Tor:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>URL de transaccions de tercers</translation> </message> <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Opcions configurades en aquest diàleg són sobreescrites per la línia de comandes o el fitxer de configuració:</translation> + </message> + <message> <source>&OK</source> <translation>&D'acord</translation> </message> @@ -1321,8 +1500,43 @@ <source>Current total balance in watch-only addresses</source> <translation>Balanç total actual en adreces de només lectura</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>El mode de privadesa està activat a la pestanya d'Overview. Per desenmascarar els valors, desmarqueu Configuració-> Valors de màscara.</translation> + </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Diàleg</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Signa Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Emet Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Còpia al Clipboard</translation> + </message> + <message> + <source>Save...</source> + <translation>Desa...</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Import total</translation> + </message> + <message> + <source>or</source> + <translation>o</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1341,6 +1555,18 @@ <translation>'bitcoin://' no és una URI vàlida. Usi 'bitcoin:' en lloc seu.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>No es pot processar la petició de pagament perquè BIP70 no està suportat.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>A causa dels defectes generalitzats en el BIP70 és altament recomanable que qualsevol instrucció comerciant per canviar carteres sigui ignorada.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Si estàs rebent aquest error, hauries de demanar al comerciant que et doni una URI compatible amb el BIP21.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>Adreça de pagament no vàlida %1</translation> </message> @@ -1418,10 +1644,34 @@ <source>%1 ms</source> <translation>%1 ms</translation> </message> + <message numerus="yes"> + <source>%n second(s)</source> + <translation><numerusform>Un segon</numerusform><numerusform>%n segons</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>Un minut</numerusform><numerusform>%n minuts</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>Una hora</numerusform><numerusform>%n hores</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>Un dia</numerusform><numerusform>%n dies</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>Una setmana</numerusform><numerusform>%n setmanes</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>Un any</numerusform><numerusform>%n anys</numerusform></translation> + </message> <message> <source>%1 B</source> <translation>%1 B</translation> @@ -1478,6 +1728,10 @@ <translation>Error en codificar l'URI en un codi QR.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>Suport de codi QR no disponible.</translation> + </message> + <message> <source>Save QR Code</source> <translation>Desa el codi QR</translation> </message> @@ -1513,10 +1767,18 @@ <translation>Datadir</translation> </message> <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>Per tal d'especificar una ubicació que no és per defecte del directori de dades utilitza la '%1' opció.</translation> + </message> + <message> <source>Blocksdir</source> <translation>Directori de blocs</translation> </message> <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>Per tal d'especificar una ubicació que no és per defecte del directori de blocs utilitza la '%1' opció.</translation> + </message> + <message> <source>Startup time</source> <translation>&Temps d'inici</translation> </message> @@ -1537,10 +1799,6 @@ <translation>Cadena de blocs</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Nombre de blocs actuals</translation> - </message> - <message> <source>Memory Pool</source> <translation>Reserva de memòria</translation> </message> @@ -1585,10 +1843,6 @@ <translation>Seleccioneu un igual per mostrar informació detallada.</translation> </message> <message> - <source>Whitelisted</source> - <translation>A la llista blanca</translation> - </message> - <message> <source>Direction</source> <translation>Direcció</translation> </message> @@ -1609,10 +1863,22 @@ <translation>Blocs sincronitzats</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>El sistema autònom de mapat utilitzat per diversificar la selecció entre iguals.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapat com</translation> + </message> + <message> <source>User Agent</source> <translation>Agent d'usuari</translation> </message> <message> + <source>Node window</source> + <translation>Finestra node</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>Obre el fitxer de registre de depuració %1 del directori de dades actual. Això pot trigar uns segons en fitxers de registre grans.</translation> </message> @@ -1629,10 +1895,6 @@ <translation>Serveis</translation> </message> <message> - <source>Ban Score</source> - <translation>Puntuació de bandeig</translation> - </message> - <message> <source>Connection Time</source> <translation>Temps de connexió</translation> </message> @@ -1781,14 +2043,6 @@ <translation>Sortint</translation> </message> <message> - <source>Yes</source> - <translation>Sí</translation> - </message> - <message> - <source>No</source> - <translation>No</translation> - </message> - <message> <source>Unknown</source> <translation>Desconegut</translation> </message> @@ -1824,6 +2078,18 @@ <translation>Un import opcional per sol·licitar. Deixeu-ho en blanc o zero per no sol·licitar cap import específic.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Una etiqueta opcional per associar-se a la nova adreça de recepció (usada per vostè per identificar una factura). També s’adjunta a la sol·licitud de pagament.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Un missatge opcional adjunt a la sol·licitud de pagament i que es pot mostrar al remitent.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Creeu una nova adreça de recepció</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>Neteja tots els camps del formulari.</translation> </message> @@ -1875,12 +2141,24 @@ <source>Copy amount</source> <translation>Copia l'import</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>No s'ha pogut desblocar la cartera.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Codi QR</translation> + <source>Amount:</source> + <translation>Import:</translation> + </message> + <message> + <source>Message:</source> + <translation>Missatge:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Moneder:</translation> </message> <message> <source>Copy &URI</source> @@ -1902,30 +2180,6 @@ <source>Payment information</source> <translation>Informació de pagament</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adreça</translation> - </message> - <message> - <source>Amount</source> - <translation>Import</translation> - </message> - <message> - <source>Label</source> - <translation>Etiqueta</translation> - </message> - <message> - <source>Message</source> - <translation>Missatge</translation> - </message> - <message> - <source>Wallet</source> - <translation>Cartera</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2073,6 +2327,18 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Polsim:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Amagueu la configuració de les tarifes de transacció</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Quan no hi ha prou espai en els blocs per encabir totes les transaccions, els miners i així mateix els nodes repetidors poden exigir una taxa mínima. És acceptable pagar únicament la taxa mínima, però tingueu present que pot resultar que la vostra transacció no sigui mai confirmada mentre hi hagi més demanda de transaccions bitcoin de les que la xarxa pot processar.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>Una taxa massa baixa pot resultar en una transacció que no es confirmi mai (llegiu el consell)</translation> + </message> + <message> <source>Confirmation time target:</source> <translation>Temps de confirmació objectiu:</translation> </message> @@ -2133,14 +2399,30 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>%1 (%2 blocs)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Creació sense firmar</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Crea una transacció bitcoin parcialment signada (PSBT) per a utilitzar, per exemple, amb una cartera %1 fora de línia o amb una cartera compatible amb PSBT.</translation> + </message> + <message> <source> from wallet '%1'</source> <translation>de la cartera "%1"</translation> </message> <message> + <source>%1 to '%2'</source> + <translation>%1 a '%2'</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 a %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Voleu redactar aquesta transacció?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Esteu segur que ho voleu enviar?</translation> </message> @@ -2161,14 +2443,34 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Comissió de transacció</translation> </message> <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Substitució per tarifa sense senyalització, BIP-125</translation> + </message> + <message> <source>Total Amount</source> <translation>Import total</translation> </message> <message> + <source>To review recipient list click "Show Details..."</source> + <translation>Per revisar la llista de destinataris, feu clic a "Mostra els detalls ..."</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Confirma l'enviament de monedes</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Confirmeu la proposta de transacció</translation> + </message> + <message> + <source>Send</source> + <translation>Enviar</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Saldo només de vigilància:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>L'adreça del destinatari no és vàlida. Torneu-la a comprovar.</translation> </message> @@ -2200,6 +2502,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <source>Payment request expired.</source> <translation>La sol·licitud de pagament ha vençut.</translation> </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>S’estima que comenci la confirmació dintre d'un bloc.</numerusform><numerusform>S’estima que comenci la confirmació dintre de %n blocs.</numerusform></translation> + </message> <message> <source>Warning: Invalid Bitcoin address</source> <translation>Avís: adreça Bitcoin no vàlida</translation> @@ -2260,6 +2566,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Elimina aquesta entrada</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>L’import a enviar a la unitat seleccionada</translation> + </message> + <message> <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source> <translation>La comissió es deduirà de l'import que s'enviarà. El destinatari rebrà menys bitcoins que les que introduïu al camp d'import. Si se seleccionen múltiples destinataris, la comissió es dividirà per igual.</translation> </message> @@ -2386,6 +2696,14 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>L'adreça Bitcoin amb què va ser signat el missatge</translation> </message> <message> + <source>The signed message to verify</source> + <translation>El missatge signat per verificar</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>La signatura donada quan es va signar el missatge</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Verificar el missatge per assegurar-se que ha estat signat amb una adreça Bitcoin específica</translation> </message> @@ -2418,6 +2736,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>S'ha cancel·lat el desblocatge de la cartera.</translation> </message> <message> + <source>No error</source> + <translation>Cap error</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>La clau privada per a la adreça introduïda no està disponible.</translation> </message> @@ -2459,6 +2781,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 </context> <context> <name>TransactionDesc</name> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Obre per un bloc més</numerusform><numerusform>Obre per %n blocs més</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Obert fins %1</translation> @@ -2535,6 +2861,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <source>Credit</source> <translation>Crèdit</translation> </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>madura en un bloc més</numerusform><numerusform>madura en %n blocs més</numerusform></translation> + </message> <message> <source>not accepted</source> <translation>no acceptat</translation> @@ -2584,6 +2914,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Índex de resultats</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(El certificat no s'ha verificat)</translation> + </message> + <message> <source>Merchant</source> <translation>Mercader</translation> </message> @@ -2641,6 +2975,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <source>Label</source> <translation>Etiqueta</translation> </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Obre per un bloc més</numerusform><numerusform>Obre per %n blocs més</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Obert fins %1</translation> @@ -2902,12 +3240,24 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <source>Close wallet</source> <translation>Tanca la cartera</translation> </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Segur que voleu tancar la cartera <i>%1 </i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Si tanqueu la cartera durant massa temps, es pot haver de tornar a sincronitzar tota la cadena si teniu el sistema de poda habilitat.</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Tanqueu totes les carteres</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>No s'ha carregat cap cartera.</translation> + <source>Create a new wallet</source> + <translation>Crear una nova cartera</translation> </message> </context> <context> @@ -2929,6 +3279,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Voleu augmentar la tarifa?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Voleu redactar una transacció amb augment de tarifes?</translation> + </message> + <message> <source>Current fee:</source> <translation>tarifa actual:</translation> </message> @@ -2945,6 +3299,14 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Confirmeu el recàrrec de tarifes</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>No es pot redactar la transacció.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT copiada</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>No es pot signar la transacció.</translation> </message> @@ -2968,6 +3330,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Exporta les dades de la pestanya actual a un fitxer</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Còpia de seguretat de la cartera</translation> </message> @@ -3011,10 +3377,6 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Poda: la darrera sincronització de la cartera va més enllà de les dades podades. Cal que activeu -reindex (baixeu tota la cadena de blocs de nou en cas de node podat)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Error: s'ha produït un error intern fatal. Vegeu debug.log per a més detalls</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>S'està podant la cadena de blocs...</translation> </message> @@ -3031,6 +3393,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>No es pot obtenir un bloqueig al directori de dades %s. %s probablement ja s'estigui executant.</translation> </message> <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>No es poden proporcionar connexions específiques i no es poden trobar connexions sortint al mateix temps.</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>S'ha produït un error en llegir %s. Totes les claus es llegeixen correctament, però les dades de la transacció o les entrades de la llibreta d'adreces podrien faltar o ser incorrectes.</translation> </message> @@ -3071,14 +3437,6 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Avís: sembla que no estem plenament d'acord amb els nostres iguals! Podria caler que actualitzar l'aplicació, o potser que ho facin altres nodes.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d dels últims 100 blocs tenen una versió inesperada</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s està malmès, el rescat de les dades ha fallat</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool ha de tenir almenys %d MB</translation> </message> @@ -3091,6 +3449,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Canvieu l'índex fora de l'abast</translation> </message> <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Configuració per a %s únicament aplicada a %s de la xarxa quan es troba a la secció [%s].</translation> + </message> + <message> <source>Copyright (C) %i-%i</source> <translation>Copyright (C) %i-%i</translation> </message> @@ -3099,6 +3461,14 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>S'ha detectat una base de dades de blocs corrupta</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>No s'ha pogut trobar el fitxer asmap %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>No s'ha pogut analitzar el fitxer asmap %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Voleu reconstruir la base de dades de blocs ara?</translation> </message> @@ -3115,6 +3485,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Error carregant %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Error carregant %s: les claus privades només es poden desactivar durant la creació</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>S'ha produït un error en carregar %s: la cartera és corrupta</translation> </message> @@ -3135,6 +3509,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Ha fallat escoltar a qualsevol port. Feu servir -listen=0 si voleu fer això.</translation> </message> <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>No s'ha pogut escanejar novament la cartera durant la inicialització</translation> + </message> + <message> <source>Importing...</source> <translation>S'està important...</translation> </message> @@ -3147,6 +3525,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>S'ha produït un error en la verificació de sanejament d'inicialització. S'està tancant %s.</translation> </message> <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Permís P2P no vàlid: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation>Import invàlid per -%s=<amount>: '%s'</translation> </message> @@ -3159,6 +3541,22 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Import invàlid per -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>El directori de blocs especificat "%s" no existeix.</translation> + </message> + <message> + <source>Unknown address type '%s'</source> + <translation>Tipus d'adreça desconegut '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Tipus de canvi desconegut '%s'</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>Actualitzant txindex de la base de dades</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>S'estan carregant les adreces P2P ...</translation> </message> @@ -3247,6 +3645,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>S'ha produït un error en actualitzar la base de dades de chainstate</translation> </message> <message> + <source>Error: Disk space is low for %s</source> + <translation>Error: l'espai del disc és insuficient per a %s</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Adreça o nom de l'ordinador -onion no vàlida: '%s'</translation> </message> @@ -3267,6 +3669,10 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Cal especificar un port amb -whitebind: «%s»</translation> </message> <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>El mode de poda no és compatible amb -blockfilterindex.</translation> + </message> + <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> <translation>Reducció de -maxconnections de %d a %d, a causa de les limitacions del sistema.</translation> </message> @@ -3279,6 +3685,24 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Ha fallat la signatura de la transacció</translation> </message> <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>-Walletdir especificat "%s" no existeix</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>-Walletdir especificat "%s" és una ruta relativa</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>-Walletdir especificat "%s" no és un directori</translation> + </message> + <message> + <source>The specified config file %s does not exist +</source> + <translation>El fitxer de configuració especificat %s no existeix +</translation> + </message> + <message> <source>The transaction amount is too small to pay the fee</source> <translation>L'import de la transacció és massa petit per pagar-ne una comissió</translation> </message> @@ -3299,10 +3723,18 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>No s'ha pogut vincular a %s en aquest ordinador (la vinculació ha retornat l'error %s)</translation> </message> <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>No es pot crear el fitxer PID '%s': %s</translation> + </message> + <message> <source>Unable to generate initial keys</source> <translation>No s'han pogut generar les claus inicials</translation> </message> <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Valor %s -blockfilterindex desconegut</translation> + </message> + <message> <source>Verifying wallet(s)...</source> <translation>S'estan verificant les carteres...</translation> </message> @@ -3311,10 +3743,6 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Avís: regles noves desconegudes activades (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Se suprimeixen totes les transaccions de la cartera..</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee especificat molt alt! Comissions tan grans podrien pagar-se en una única transacció.</translation> </message> @@ -3327,10 +3755,6 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>La longitud total de la cadena de la versió de xarxa (%i) supera la longitud màxima (%i). Redueix el nombre o la mida de uacomments.</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>Advertència: la cartera és malmesa, les dades es recuperen! Original %s desat com a %s en %s; si el vostre saldo o transaccions són incorrectes, haureu de restaurar des d'una còpia de seguretat.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s està especificat molt alt!</translation> </message> @@ -3375,6 +3799,14 @@ Nota: Com que la comissió es calcula en funció dels bytes, una comissió de "1 <translation>Balanç insuficient</translation> </message> <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>L'estimació de la quota ha fallat. Fallbackfee està desactivat. Espereu uns quants blocs o activeu -fallbackfee.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Avís: Claus privades detectades en la cartera {%s} amb claus privades deshabilitades</translation> + </message> + <message> <source>Cannot write to data directory '%s'; check permissions.</source> <translation>No es pot escriure en el directori de dades "%s". Reviseu-ne els permisos.</translation> </message> diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 70334087e8..1ba16439a7 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -43,7 +43,7 @@ </message> <message> <source>&Delete</source> - <translation>S&maž</translation> + <translation>&Smaž</translation> </message> <message> <source>Choose the address to send coins to</source> @@ -70,8 +70,9 @@ <translation>Tohle jsou tvé bitcoinové adresy pro posílání plateb. Před odesláním mincí si vždy zkontroluj částku a cílovou adresu.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Tohle jsou tvé bitcoinové adresy pro příjem plateb. Použij 'Vytvoř novou přijímací adresu' v záložce Přijmi pro vytvoření nové adresy.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Tohle jsou tvé bitcoinové adresy pro přijmaní plateb. Použij "Vytvoř novou přijimací adresu" pro vytvoření nových adres. Přihlašování je povoleno jen s adresami typu "Legacy"</translation> </message> <message> <source>&Copy Address</source> @@ -275,7 +276,7 @@ </message> <message> <source>Browse transaction history</source> - <translation>Procházej historii transakcí</translation> + <translation>Procházet historii transakcí</translation> </message> <message> <source>E&xit</source> @@ -482,6 +483,14 @@ <translation>Aktuální</translation> </message> <message> + <source>Node window</source> + <translation>Okno uzlu</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Otevřít konzolu pro ladění a diagnostiku uzlů</translation> + </message> + <message> <source>&Sending addresses</source> <translation>Odesílací adresy</translation> </message> @@ -490,6 +499,10 @@ <translation>Přijímací adresy</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Načíst Bitcoin: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Otevřít peněženku</translation> </message> @@ -550,6 +563,10 @@ <translation>Chyba: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>Varování: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>Datum: %1 @@ -613,11 +630,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Peněženka je <b>zašifrovaná</b> a momentálně <b>zamčená</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Stala se fatální chyba. Bitcoin nemůže bezpečně pokračovat v činnosti, a proto skončí.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -771,10 +784,58 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Vytvářím peněženku <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Vytvoření peněženky selhalo</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Vytvořit varování peněženky</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Vytvořit peněženku</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Název peněženky</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Zašifrovat peněženku. Peněženka bude zašifrována pomocí vašeho hesla.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Zašifrovat peněženku</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Vypnout soukromé klíče pro tuto peněženku. Peněženky s vypnutými soukromými klíči nebudou mít soukromé klíče a nemohou mít HD inicializaci ani importované soukromé klíče. Tohle je ideální pro peněženky pouze na sledování.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Zrušit soukromé klíče</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Vytvořit prázdnou peněženku. Prázdné peněženky na začátku nemají žádné soukromé klíče ani skripty. Později mohou být importovány soukromé klíče a adresy nebo nastavená HD inicializace.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Vytvořit prázdnou peněženku</translation> + </message> + <message> + <source>Create</source> + <translation>Vytvořit</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -887,6 +948,10 @@ <translation>Jakmile stiskneš OK, %1 začne stahovat a zpracovávat celý %4ový blockchain (%2 GB), počínaje nejstaršími transakcemi z roku %3, kdy byl %4 spuštěn.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Vrácení tohoto nastavení vyžaduje opětovné stažení celého blockchainu. Je rychlejší stáhnout celý řetězec nejprve a prořezat jej později. Některé pokročilé funkce budou zakázány, dokud celý blockchain nebude stažen nanovo.</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>Prvotní synchronizace je velice náročná, a mohou se tak díky ní začít na tvém počítači projevovat dosud skryté hardwarové problémy. Pokaždé, když spustíš %1, bude stahování pokračovat tam, kde skončilo.</translation> </message> @@ -907,6 +972,10 @@ <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Zahodit bloky po ověření, s výjimkou posledních %1 GB (prořezat)</translation> + </message> + <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <translation>Bude proto potřebovat do tohoto adresáře uložit nejméně %1 GB dat – tohle číslo navíc bude v průběhu času růst.</translation> </message> @@ -938,7 +1007,11 @@ <source>(of %n GB needed)</source> <translation><numerusform>(z potřebného %n GB)</numerusform><numerusform>(z potřebných %n GB)</numerusform><numerusform>(z potřebných %n GB)</numerusform><numerusform>(z potřebných %n GB)</numerusform></translation> </message> - </context> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB potřeba pre plný řetězec)</numerusform><numerusform>(%n GB potřeba pre plný řetězec) </numerusform><numerusform>(%n GB potřeba pre plný řetězec) </numerusform><numerusform>(%n GB potřeba pre plný řetězec) </numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -986,6 +1059,14 @@ <translation>Skryj</translation> </message> <message> + <source>Esc</source> + <translation>Esc - úniková klávesa</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 se právě synchronizuje. Stáhnou se hlavičky a bloky od protějsků. Ty se budou se ověřovat až se kompletně ověří celý řetězec bloků.</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Neznámé. Synchronizace hlaviček (%1, %2)...</translation> </message> @@ -993,6 +1074,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Otevřít bitcoin URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1000,6 +1085,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Otevření peněženky selhalo</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Varování otevření peněženky</translation> + </message> + <message> <source>default wallet</source> <translation>výchozí peněženka</translation> </message> @@ -1043,10 +1136,6 @@ <translation>Ukazuje, jestli se zadaná výchozí SOCKS5 proxy používá k připojování k peerům v rámci tohoto typu sítě.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Použít samostatnou SOCKS&5 proxy ke spojení s protějšky přes skryté služby v Toru:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Skryje ikonu, která se zobrazuje v panelu.</translation> </message> @@ -1179,10 +1268,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Připojí se do bitcoinové sítě přes SOCKS5 proxy vyhrazenou pro skryté služby v Tor síti.</translation> - </message> - <message> <source>&Window</source> <translation>O&kno</translation> </message> @@ -1357,7 +1442,22 @@ <source>Current total balance in watch-only addresses</source> <translation>Aktuální stav účtu sledovaných adres</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Celková částka</translation> + </message> + <message> + <source>or</source> + <translation>nebo</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1377,6 +1477,18 @@ <translation>'bitcoin://' není platné URI. Místo toho použij 'bitcoin:'.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Nelze zpracovat žádost o platbu, protože podpora pro BIP70 není podporována.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Vzhledem k rozšířeným bezpečnostním nedostatkům v BIP70 se důrazně doporučuje, aby byly ignorovány veškeré obchodní pokyny pro přepínání peněženek.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Pokud obdržíte tuto chybu, měli byste požádat obchodníka, aby poskytl URI kompatibilní s BIP21.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>Neplatná platební adresa %1</translation> </message> @@ -1538,6 +1650,10 @@ <translation>Chyba při kódování URI do QR kódu.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>Podpora QR kódu není k dispozici.</translation> + </message> + <message> <source>Save QR Code</source> <translation>Ulož QR kód</translation> </message> @@ -1605,10 +1721,6 @@ <translation>Blockchain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Aktuální počet bloků</translation> - </message> - <message> <source>Memory Pool</source> <translation>Transakční zásobník</translation> </message> @@ -1653,10 +1765,6 @@ <translation>Vyber protějšek a uvidíš jeho detailní informace.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Vždy vítán</translation> - </message> - <message> <source>Direction</source> <translation>Směr</translation> </message> @@ -1677,10 +1785,22 @@ <translation>Aktuálně bloků</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Mapovaný nezávislý - Autonomní Systém používaný pro rozšírení vzájemného výběru protějsků.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapovaný AS</translation> + </message> + <message> <source>User Agent</source> <translation>Typ klienta</translation> </message> <message> + <source>Node window</source> + <translation>Okno uzlu</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>Otevři soubor s ladicími záznamy %1 z aktuálního datového adresáře. U velkých žurnálů to může pár vteřin zabrat.</translation> </message> @@ -1697,10 +1817,6 @@ <translation>Služby</translation> </message> <message> - <source>Ban Score</source> - <translation>Skóre pro klatbu</translation> - </message> - <message> <source>Connection Time</source> <translation>Doba spojení</translation> </message> @@ -1849,14 +1965,6 @@ <translation>Ven</translation> </message> <message> - <source>Yes</source> - <translation>Ano</translation> - </message> - <message> - <source>No</source> - <translation>Ne</translation> - </message> - <message> <source>Unknown</source> <translation>Neznámá</translation> </message> @@ -1892,6 +2000,18 @@ <translation>Volitelná částka, kterou požaduješ. Nech prázdné nebo nulové, pokud nepožaduješ konkrétní částku.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Volitelný popis který sa přidá k téjo nové přijímací adrese (pro jednoduchší identifikaci). Tenhle popis bude také přidán do výzvy k platbě.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Volitelná zpráva která se přidá k téjo platební výzvě a může být zobrazena odesílateli.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Vytvořit novou přijímací adresu</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>Promaž obsah ze všech formulářových políček.</translation> </message> @@ -1905,7 +2025,7 @@ </message> <message> <source>Generate native segwit (Bech32) address</source> - <translation>Generovat nativní segwit adresu (Bench32)</translation> + <translation>Generovat nativní segwit adresu (Bech32)</translation> </message> <message> <source>Requested payments history</source> @@ -1943,12 +2063,28 @@ <source>Copy amount</source> <translation>Kopíruj částku</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Nemohu odemknout peněženku.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR kód</translation> + <source>Amount:</source> + <translation>Částka:</translation> + </message> + <message> + <source>Label:</source> + <translation>Označení:</translation> + </message> + <message> + <source>Message:</source> + <translation>Zpráva:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Peněženka:</translation> </message> <message> <source>Copy &URI</source> @@ -1970,30 +2106,6 @@ <source>Payment information</source> <translation>Informace o platbě</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adresa</translation> - </message> - <message> - <source>Amount</source> - <translation>Částka</translation> - </message> - <message> - <source>Label</source> - <translation>Označení</translation> - </message> - <message> - <source>Message</source> - <translation>Zpráva</translation> - </message> - <message> - <source>Wallet</source> - <translation>Peněženka</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2141,6 +2253,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Prach:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Schovat nastavení poplatků transakce - transaction fee</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Když je zde měně transakcí než místa na bloky, mineři stejně tak relay-e mohou nasadit minimální poplatky. Zaplacením pouze minimálního poplatku je v pohodě, ale mějte na paměti že toto může mít za následek nikdy neověřenou transakci pokud zde bude více bitcoinových transakcí než může síť zvládnout.</translation> </message> @@ -2209,8 +2325,28 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>%1 (%2 bloků)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Vytvořit bez podpisu</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Vytvořit částečně podepsanou Bitcoin transakci (Partially Signed Bitcoin Transaction - PSBT) k použtí kupříkladu s offline %1 peněženkou nebo s jinou kompatibilní PSBT hardware peněženkou.</translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation>z peněženky '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 do '%2'</translation> + </message> + <message> <source>%1 to %2</source> - <translation>%1 pro %2</translation> + <translation>%1 do %2</translation> + </message> + <message> + <source>Do you want to draft this transaction?</source> + <translation>Chcete naplánovat tuhle transakci?</translation> </message> <message> <source>Are you sure you want to send?</source> @@ -2241,12 +2377,24 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Celková částka</translation> </message> <message> + <source>To review recipient list click "Show Details..."</source> + <translation>Chcete-li zkontrolovat seznam příjemců, klikněte na „Zobrazit podrobnosti ...“</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Potvrď odeslání mincí</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Potvrdit návrh transakce</translation> + </message> + <message> <source>Send</source> - <translation>Pošli</translation> + <translation>Odeslat</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Pouze sledovaný zůstatek:</translation> </message> <message> <source>The recipient address is not valid. Please recheck.</source> @@ -2344,6 +2492,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Smaž tento záznam</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Částka k odeslání ve vybrané měně</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>Poplatek se odečte od posílané částky. Příjemce tak dostane méně bitcoinů, než zadáš do pole Částka. Pokud vybereš více příjemců, tak se poplatek rovnoměrně rozloží.</translation> </message> @@ -2470,6 +2622,14 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Bitcoinová adresa, kterou je zpráva podepsána</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Podepsaná zpráva na ověření</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>Podpis daný při podpisu zprávy</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Ověř zprávu, aby ses ujistil, že byla podepsána danou bitcoinovou adresou</translation> </message> @@ -2502,6 +2662,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Odemčení peněženky bylo zrušeno.</translation> </message> <message> + <source>No error</source> + <translation>Bez chyby</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Soukromý klíč pro zadanou adresu není dostupný.</translation> </message> @@ -2676,6 +2840,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Pořadí výstupu</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(Certifikát nebyl ověřen)</translation> + </message> + <message> <source>Merchant</source> <translation>Obchodník</translation> </message> @@ -2999,15 +3167,19 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Zavřít peněženku</translation> </message> <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Opravdu chcete zavřít peněženku <i>%1</i>?</translation> + </message> + <message> <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Zavření peněženky na příliš dlouhou dobu může vyústit v potřebu resynchronizace celého blockchainu pokud je zapnuté prořezávání.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Žádná peněženka se nenačetla.</translation> + <source>Create a new wallet</source> + <translation>Vytvoř novou peněženku</translation> </message> </context> <context> @@ -3026,7 +3198,11 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa </message> <message> <source>Do you want to increase the fee?</source> - <translation>Chceš poplatek navýšit?</translation> + <translation>Chcete navýšit poplatek?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Chcete naplánovat tuhle transakci s navýšením poplatku?</translation> </message> <message> <source>Current fee:</source> @@ -3045,6 +3221,14 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Potvrď navýšení poplatku</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>Nelze navrhnout transakci.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT zkopírováno</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Nemůžu podepsat transakci.</translation> </message> @@ -3068,6 +3252,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Exportuj data z tohoto panelu do souboru</translation> </message> <message> + <source>Error</source> + <translation>Chyba</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Záloha peněženky</translation> </message> @@ -3111,10 +3299,6 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Prořezávání: poslední synchronizace peněženky proběhla před už prořezanými daty. Je třeba provést -reindex (tedy v případě prořezávacího režimu stáhnout znovu celý blockchain)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Chyba: Přihodila se závažná vnitřní chyba, podrobnosti viz v debug.log</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Prořezávám úložiště bloků...</translation> </message> @@ -3127,10 +3311,6 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Vývojáři %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Nelze vygenerovat klíč pro změnu adresy. Nejsou žádní klíče v key-poolu a tedy nemůžeme žádné klíče vygenerovat.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Nedaří se mi získat zámek na datový adresář %s. %s pravděpodobně už jednou běží.</translation> </message> @@ -3179,14 +3359,6 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Upozornění: Nesouhlasím zcela se svými protějšky! Možná potřebuji aktualizovat nebo ostatní uzly potřebují aktualizovat.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d z posledních 100 bloků má neočekávanou verzi</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s je poškozen, jeho záchrana se nezdařila</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool musí být alespoň %d MB</translation> </message> @@ -3211,6 +3383,14 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Bylo zjištěno poškození databáze bloků</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>Soubor asmap nelze najít %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Soubor asmap nelze analyzovat %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Chceš přestavět databázi bloků hned teď?</translation> </message> @@ -3267,6 +3447,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Selhala úvodní zevrubná prověrka. %s se ukončuje.</translation> </message> <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Neplatné oprávnenie P2P: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation>Neplatná částka pro -%s=<částka>: '%s'</translation> </message> @@ -3283,6 +3467,14 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Zadaný adresář bloků "%s" neexistuje.</translation> </message> <message> + <source>Unknown address type '%s'</source> + <translation>Neznámý typ adresy '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Neznámý typ změny '%s'</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Aktualizuje se txindex databáze</translation> </message> @@ -3399,6 +3591,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>V rámci -whitebind je třeba specifikovat i port: '%s'</translation> </message> <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Režim prořezávání není kompatibilní s -blockfilterindex.</translation> + </message> + <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> <translation>Omezuji -maxconnections z %d na %d kvůli systémovým omezením.</translation> </message> @@ -3457,6 +3653,10 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Nepodařilo se mi vygenerovat počáteční klíče</translation> </message> <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Neznámá -blockfilterindex hodnota %s.</translation> + </message> + <message> <source>Verifying wallet(s)...</source> <translation>Kontroluji peněženku/y…</translation> </message> @@ -3465,10 +3665,6 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Upozornění: aktivována neznámá nová pravidla (verzový bit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Vymazat všechny transakce z peněženky...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee je nastaveno velmi vysoko! Takto vysoký poplatek může být zaplacen v jednotlivé transakci.</translation> </message> @@ -3481,10 +3677,6 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Celková délka síťového identifikačního řetězce (%i) překročila svůj horní limit (%i). Omez počet nebo velikost voleb uacomment.</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>Upozornění: soubor s peněženkou je poškozený, data jsou však zachráněna! Původní soubor %s je uložený jako %s v %s. Pokud nejsou stav tvého účtu nebo transakce v pořádku, zřejmě bys měl obnovit zálohu.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s je nastaveno velmi vysoko!</translation> </message> @@ -3529,10 +3721,6 @@ Poznámka: Jelikož je poplatek počítaný za bajt, poplatek o hodnotě "100 sa <translation>Nedostatek prostředků</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> diff --git a/src/qt/locale/bitcoin_cy.ts b/src/qt/locale/bitcoin_cy.ts index 3f053f7be6..cd1fe6232c 100644 --- a/src/qt/locale/bitcoin_cy.ts +++ b/src/qt/locale/bitcoin_cy.ts @@ -525,11 +525,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Mae'r waled <b>wedi'i amgryptio</b> ac <b>ar glo</b> ar hyn o bryd</translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Mae gwall angheuol wedi digwydd. Ni all Bitcoin barhau'n ddiogel ac mae'n cau lawr.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -739,6 +735,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -791,34 +790,30 @@ <source>Copy amount</source> <translation>Copïo Cyfanswm</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> - <message> - <source>Copy &Address</source> - <translation>&Cyfeiriad Copi</translation> - </message> <message> - <source>Address</source> - <translation>Cyfeiriad</translation> + <source>Could not unlock wallet.</source> + <translation>Methodd ddatgloi'r waled.</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Amount</source> - <translation>Cyfanswm</translation> + <source>Amount:</source> + <translation>Maint</translation> </message> <message> - <source>Label</source> - <translation>Label</translation> + <source>Message:</source> + <translation>Neges:</translation> </message> <message> - <source>Message</source> - <translation>Neges</translation> + <source>Wallet:</source> + <translation>Waled:</translation> </message> <message> - <source>Wallet</source> - <translation>Waled</translation> + <source>Copy &Address</source> + <translation>&Cyfeiriad Copi</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1095,6 +1090,10 @@ <source>Export the data in the current tab to a file</source> <translation>Allforio'r data yn y tab presennol i ffeil</translation> </message> + <message> + <source>Error</source> + <translation>Gwall</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts index 0fb4d104aa..2fd4955ca8 100644 --- a/src/qt/locale/bitcoin_da.ts +++ b/src/qt/locale/bitcoin_da.ts @@ -70,10 +70,6 @@ <translation>Disse er dine Bitcoin-adresser til afsendelse af betalinger. Tjek altid beløb og modtagelsesadresse, inden du sender bitcoins.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Disse er dine Bitcoin adresser til at modtage betalinger. Benyt 'Opret ny modtager adresse' knappen i modtag fanen for at oprette nye adresser.</translation> - </message> - <message> <source>&Copy Address</source> <translation>&Kopiér adresse</translation> </message> @@ -629,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Tegnebog er <b>krypteret</b> og i øjeblikket <b>låst</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Der opstod en fatal fejl. Bitcoin kan ikke længere fortsætte sikkert og vil afslutte.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -1139,10 +1131,6 @@ <translation>Viser om den angivne standard-SOCKS5-proxy bruges til at nå knuder via denne netværkstype.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Brug separat SOCKS&5-proxy for at nå knuder via Tors skjulte tjenester:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Skjul ikonet fra statusfeltet.</translation> </message> @@ -1275,10 +1263,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Forbind til Bitcoin-netværket gennem en separat SOCKS5-proxy for Tors skjulte tjenester.</translation> - </message> - <message> <source>&Window</source> <translation>&Vindue</translation> </message> @@ -1453,7 +1437,22 @@ <source>Current total balance in watch-only addresses</source> <translation>Nuværende totalsaldo på kigge-adresser</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Total Mængde</translation> + </message> + <message> + <source>or</source> + <translation>eller</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1717,10 +1716,6 @@ <translation>Blokkæde</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Nuværende antal blokke</translation> - </message> - <message> <source>Memory Pool</source> <translation>Hukommelsespulje</translation> </message> @@ -1765,10 +1760,6 @@ <translation>Vælg en anden knude for at se detaljeret information.</translation> </message> <message> - <source>Whitelisted</source> - <translation>På hvidliste</translation> - </message> - <message> <source>Direction</source> <translation>Retning</translation> </message> @@ -1789,6 +1780,14 @@ <translation>Synkroniserede blokke</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Afbildning fra Autonome Systemer (et Internet-Protocol-rutefindingsprefiks) til IP-adresser som bruges til at diversificere knudeforbindelser. Den engelske betegnelse er "asmap".</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Autonomt-System-afbildning</translation> + </message> + <message> <source>User Agent</source> <translation>Brugeragent</translation> </message> @@ -1813,10 +1812,6 @@ <translation>Tjenester</translation> </message> <message> - <source>Ban Score</source> - <translation>Bandlysningsscore</translation> - </message> - <message> <source>Connection Time</source> <translation>Forbindelsestid</translation> </message> @@ -1965,14 +1960,6 @@ <translation>Udgående</translation> </message> <message> - <source>Yes</source> - <translation>Ja</translation> - </message> - <message> - <source>No</source> - <translation>Nej</translation> - </message> - <message> <source>Unknown</source> <translation>Ukendt</translation> </message> @@ -2071,12 +2058,28 @@ <source>Copy amount</source> <translation>Kopiér beløb</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Kunne ikke låse tegnebog op.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-kode</translation> + <source>Amount:</source> + <translation>Beløb:</translation> + </message> + <message> + <source>Label:</source> + <translation>Mærkat:</translation> + </message> + <message> + <source>Message:</source> + <translation>Besked:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Tegnebog:</translation> </message> <message> <source>Copy &URI</source> @@ -2098,30 +2101,6 @@ <source>Payment information</source> <translation>Betalingsinformation</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adresse</translation> - </message> - <message> - <source>Amount</source> - <translation>Beløb</translation> - </message> - <message> - <source>Label</source> - <translation>Mærkat</translation> - </message> - <message> - <source>Message</source> - <translation>Besked</translation> - </message> - <message> - <source>Wallet</source> - <translation>Tegnebog</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2401,18 +2380,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Bekræft transaktionsudkast</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Kopiér PSBT til udklipsholderen</translation> - </message> - <message> <source>Send</source> <translation>Afsend</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT kopieret</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Kiggebalance:</translation> </message> @@ -3194,12 +3165,12 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Lukning af tegnebog i for lang tid kan resultere i at synkronisere hele kæden forfra, hvis beskæring er aktiveret.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Ingen tegnebog er indlæst.</translation> + <source>Create a new wallet</source> + <translation>Opret en ny tegnebog</translation> </message> </context> <context> @@ -3272,6 +3243,10 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Eksportér den aktuelle visning til en fil</translation> </message> <message> + <source>Error</source> + <translation>Fejl</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Sikkerhedskopiér tegnebog</translation> </message> @@ -3315,10 +3290,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Beskæring: Seneste synkronisering rækker udover beskårne data. Du er nødt til at bruge -reindex (downloade hele blokkæden igen i fald af beskåret knude)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Fejl: En alvorlig intern fejl er opstået. Se debug.log for detaljer</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Beskærer bloklager…</translation> </message> @@ -3331,10 +3302,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Udviklerne af %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Kan ikke generere en bytte-adresse nøgle. Ingen nøgler i den interne nøglepulje og kan ikke generere nogle nøgler.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Kan ikke opnå en lås på datamappe %s. %s kører sansynligvis allerede.</translation> </message> @@ -3383,14 +3350,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Advarsel: Vi ser ikke ud til at være fuldt ud enige med andre knuder! Du kan være nødt til at opgradere, eller andre knuder kan være nødt til at opgradere.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d af de seneste 100 blokke har en uventet version</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s ødelagt, redning af data mislykkedes</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool skal være mindst %d MB</translation> </message> @@ -3515,10 +3474,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Indlæser P2P-adresser…</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Fejl: Disk pladsen er for lav!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Indlæser bandlysningsliste…</translation> </message> @@ -3701,10 +3656,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Advarsel: Ukendte nye regler aktiveret (versionsbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Zapper alle transaktioner fra tegnebog…</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee er sat meget højt! Gebyrer så store risikeres betalt på en enkelt transaktion.</translation> </message> @@ -3717,10 +3668,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Den totale længde på netværksversionsstrengen (%i) overstiger maksimallængden (%i). Reducér antaller af eller størrelsen på uacomments.</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>Advarsel: Tegnebogsfil ødelagt, data reddet! Oprindelig %s gemt som %s i %s; hvis din saldo eller dine transaktioner er forkert, bør du genskabe fra en sikkerhedskopi.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s er meget højt sat!</translation> </message> @@ -3765,10 +3712,6 @@ Note: Siden gebyret er kalkuleret på en per-byte basis, et gebyr på "100 satos <translation>Manglende dækning</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 ikke opgradere en ikke HD dele tegnebog uden opgradering til at støtte før split nøglepool. Venligst brug -upgradewallet=169900 eller -upgradewallet med ingen version specificeret.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Estimering af gebyr mislykkedes. Tilbagefaldsgebyr er deaktiveret. Vent et par blokke eller aktiver -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index ff763b002c..659a29bc29 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Rechtsklick zum Bearbeiten der Adresse oder der Bezeichnung</translation> + <translation>Rechtsklick zum Bearbeiten der Adresse oder der Beschreibung</translation> </message> <message> <source>Create a new address</source> @@ -70,8 +70,10 @@ <translation>Dies sind Ihre Bitcoin-Adressen zum Tätigen von Überweisungen. Bitte prüfen Sie den Betrag und die Adresse des Empfängers, bevor Sie Bitcoins überweisen.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Dies sind Ihre Bitcoin-Adressen zum Empfangen von Zahlungen. Benutze den 'Neue Empfangsadresse erstellen' Button im Empfangen-Tab, um eine neue Addresse zu erstellen.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Dies sind Ihre Bitcoin-Adressen für den Empfang von Zahlungen. Verwenden Sie die 'Neue Empfangsadresse erstellen' Taste auf der Registerkarte "Empfangen", um neue Adressen zu erstellen. +Das Signieren ist nur mit Adressen vom Typ 'Legacy' möglich.</translation> </message> <message> <source>&Copy Address</source> @@ -482,6 +484,22 @@ <translation>Auf aktuellem Stand</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Lade PSBT aus Datei...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Lade teilsignierte Bitcoin-Transaktion</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Lade PSBT aus Zwischenablage</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Lade teilsignierte Bitcoin-Transaktion aus Zwischenablage</translation> + </message> + <message> <source>Node window</source> <translation>Node Fenster</translation> </message> @@ -518,10 +536,26 @@ <translation>Wallet schließen</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Schließe alle Wallets...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Schließe alle Wallets</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Zeige den "%1"-Hilfetext, um eine Liste mit möglichen Kommandozeilenoptionen zu erhalten</translation> </message> <message> + <source>&Mask values</source> + <translation>&Blende Werte aus</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Blende die Werte im Übersichtsreiter aus</translation> + </message> + <message> <source>default wallet</source> <translation>Standard Wallet</translation> </message> @@ -630,8 +664,12 @@ <translation>Wallet ist <b>verschlüsselt</b> und aktuell <b>gesperrt</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Ein schwerer Fehler ist aufgetreten. Bitcoin kann nicht stabil weiter ausgeführt werden und wird beendet.</translation> + <source>Original message:</source> + <translation>Original-Nachricht:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Ein fataler Fehler ist aufgetreten. %1 kann nicht länger sicher fortfahren und wird beendet.</translation> </message> </context> <context> @@ -658,7 +696,7 @@ </message> <message> <source>Dust:</source> - <translation>"Dust":</translation> + <translation>"Staub":</translation> </message> <message> <source>After Fee:</source> @@ -808,7 +846,7 @@ </message> <message> <source>Wallet Name</source> - <translation>Wallet Name</translation> + <translation>Wallet-Name</translation> </message> <message> <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> @@ -835,6 +873,14 @@ <translation>Eine leere Wallet erstellen</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Deskriptoren für scriptPubKey Verwaltung nutzen</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Deskriptor Brieftasche</translation> + </message> + <message> <source>Create</source> <translation>Erstellen</translation> </message> @@ -1012,7 +1058,7 @@ </message> <message numerus="yes"> <source>(%n GB needed for full chain)</source> - <translation><numerusform>(%n GB benötigt für komplette Blockchain)</numerusform><numerusform>(%n GB benötigt für komplette Blockchain)</numerusform></translation> + <translation><numerusform>(%n GB benötigt für komplette Blockchain)</numerusform><numerusform>(%n GB wird die komplette Blockchain benötigen)</numerusform></translation> </message> </context> <context> @@ -1067,7 +1113,7 @@ </message> <message> <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> - <translation>%1 synchronisiert gerade. Es lädt Header und Blöcke von anderen Nodes und validiert sie bis zum Erreichen der Spitze der Blockkette.</translation> + <translation>%1 synchronisiert gerade. Es lädt Header und Blöcke von Gegenstellen und validiert sie bis zum Erreichen der Spitze der Blockkette.</translation> </message> <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> @@ -1097,11 +1143,11 @@ </message> <message> <source>default wallet</source> - <translation>Standard Wallet</translation> + <translation>Standard-Wallet</translation> </message> <message> <source>Opening Wallet <b>%1</b>...</source> - <translation>Öffne Wallet<b>%1</b> ...</translation> + <translation>Öffne Wallet <b>%1</b> ...</translation> </message> </context> <context> @@ -1124,7 +1170,7 @@ </message> <message> <source>Size of &database cache</source> - <translation>Größe des &Datenbankcaches</translation> + <translation>Größe des &Datenbankpufferspeichers</translation> </message> <message> <source>Number of script &verification threads</source> @@ -1139,10 +1185,6 @@ <translation>Zeigt an, ob der gelieferte Standard SOCKS5 Proxy verwendet wurde, um die Peers mit diesem Netzwerktyp zu erreichen.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Separaten SOCKS5-Proxy verwenden, um Gegenstellen über versteckte Tor-Dienste zu erreichen:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Verstecke das Icon von der Statusleiste.</translation> </message> @@ -1275,10 +1317,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Über einen separaten SOCKS5 Proxy für Tor Hidden Services mit dem Bitcoin-Netzwerk verbinden.</translation> - </message> - <message> <source>&Window</source> <translation>&Programmfenster</translation> </message> @@ -1319,6 +1357,10 @@ <translation>Legt fest, ob die "Coin Control"-Funktionen angezeigt werden.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Verbinde mit dem Bitcoin-Netzwerk über einen separaten SOCKS5-Proxy für Tor-/Onion-Dienste.</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&Externe Transaktions-URLs</translation> </message> @@ -1453,6 +1495,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Aktueller Gesamtbetrag in nur-beobachteten Adressen</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Datenschutz-Modus aktiviert für den Übersichtsreiter. Um die Werte einzublenden, Einstellungen->Werte ausblenden deaktivieren.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Signiere Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Rundsende Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Kopiere in Zwischenablage</translation> + </message> + <message> + <source>Save...</source> + <translation>Speichern...</translation> + </message> + <message> + <source>Close</source> + <translation>Schließen</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Laden der Transaktion fehlgeschlagen: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Signieren der Transaktion fehlgeschlagen: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Konnte keinerlei weitere Eingaben signieren.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>%1 Eingaben signiert, doch noch sind weitere Signaturen erforderlich.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Transaktion erfolgreich signiert. Transaktion ist bereit für Rundsendung.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Unbekannter Fehler bei der Transaktionsverarbeitung</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Transaktion erfolgreich rundgesendet! Transaktions-ID: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Rundsenden der Transaktion fehlgeschlagen: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT in Zwischenablage kopiert.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Speichere Transaktionsdaten</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Teilsignierte Transaktion (Binärdatei) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT auf Platte gespeichert.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>* Sende %1 an %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Kann die Gebühr oder den Gesamtbetrag der Transaktion nicht berechnen.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Zahlt Transaktionsgebühr:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Gesamtbetrag</translation> + </message> + <message> + <source>or</source> + <translation>oder</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Transaktion hat %1 unsignierte Eingaben.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Der Transaktion fehlen einige Informationen über Eingaben.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Transaktion erfordert weiterhin Signatur(en).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(doch diese Wallet kann Transaktionen nicht signieren)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(doch diese Wallet hat nicht die richtigen Schlüssel)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Transaktion ist vollständig signiert und zur Rundsendung bereit.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Transaktionsstatus ist unbekannt.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1619,6 +1788,10 @@ <translation>Fehler: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Fehler beim Initialisieren der Einstellungen: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 wurde noch nicht sicher beendet...</translation> </message> @@ -1717,10 +1890,6 @@ <translation>Blockchain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Aktuelle Anzahl der Blöcke</translation> - </message> - <message> <source>Memory Pool</source> <translation>Speicher-Pool</translation> </message> @@ -1758,17 +1927,13 @@ </message> <message> <source>Banned peers</source> - <translation>Gesperrte Peers</translation> + <translation>Gesperrte Gegenstellen</translation> </message> <message> <source>Select a peer to view detailed information.</source> <translation>Gegenstelle auswählen, um detaillierte Informationen zu erhalten.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Auf Weißliste</translation> - </message> - <message> <source>Direction</source> <translation>Richtung</translation> </message> @@ -1789,6 +1954,14 @@ <translation>Synchronisierte Blöcke</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Das zugeordnete autonome System zur Diversifizierung der Gegenstellen-Auswahl.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Zugeordnetes AS</translation> + </message> + <message> <source>User Agent</source> <translation>User-Agent</translation> </message> @@ -1797,6 +1970,10 @@ <translation>Node Fenster</translation> </message> <message> + <source>Current block height</source> + <translation>Aktuelle Blockhöhe</translation> + </message> + <message> <source>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source> <translation>Öffnet die %1-Debug-Protokolldatei aus dem aktuellen Datenverzeichnis. Dies kann bei großen Protokolldateien einige Sekunden dauern.</translation> </message> @@ -1809,12 +1986,12 @@ <translation>Schrift vergrößern</translation> </message> <message> - <source>Services</source> - <translation>Dienste</translation> + <source>Permissions</source> + <translation>Berechtigungen</translation> </message> <message> - <source>Ban Score</source> - <translation>Sperrpunktzahl</translation> + <source>Services</source> + <translation>Dienste</translation> </message> <message> <source>Connection Time</source> @@ -1965,14 +2142,6 @@ <translation>ausgehend</translation> </message> <message> - <source>Yes</source> - <translation>Ja</translation> - </message> - <message> - <source>No</source> - <translation>Nein</translation> - </message> - <message> <source>Unknown</source> <translation>Unbekannt</translation> </message> @@ -2071,56 +2240,60 @@ <source>Copy amount</source> <translation>Betrag kopieren</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Wallet konnte nicht entsperrt werden.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Konnte neue %1 Adresse nicht erzeugen.</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-Code</translation> + <source>Request payment to ...</source> + <translation>Zahlung anfordern an ...</translation> </message> <message> - <source>Copy &URI</source> - <translation>&URI kopieren</translation> + <source>Address:</source> + <translation>Adresse:</translation> </message> <message> - <source>Copy &Address</source> - <translation>&Adresse kopieren</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>Grafik &speichern...</translation> + <source>Amount:</source> + <translation>Betrag:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Zahlung anfordern an %1</translation> + <source>Label:</source> + <translation>Bezeichnung:</translation> </message> <message> - <source>Payment information</source> - <translation>Zahlungsinformationen</translation> + <source>Message:</source> + <translation>Nachricht:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Wallet:</translation> </message> <message> - <source>Address</source> - <translation>Adresse</translation> + <source>Copy &URI</source> + <translation>&URI kopieren</translation> </message> <message> - <source>Amount</source> - <translation>Betrag</translation> + <source>Copy &Address</source> + <translation>&Adresse kopieren</translation> </message> <message> - <source>Label</source> - <translation>Bezeichnung</translation> + <source>&Save Image...</source> + <translation>Grafik &speichern...</translation> </message> <message> - <source>Message</source> - <translation>Nachricht</translation> + <source>Request payment to %1</source> + <translation>Zahlung anfordern an %1</translation> </message> <message> - <source>Wallet</source> - <translation>Wallet</translation> + <source>Payment information</source> + <translation>Zahlungsinformationen</translation> </message> </context> <context> @@ -2266,7 +2439,7 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio </message> <message> <source>Dust:</source> - <translation>"Dust":</translation> + <translation>"Staub":</translation> </message> <message> <source>Hide transaction fee settings</source> @@ -2369,8 +2542,20 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Wollen Sie die Überweisung ausführen?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Bitte überprüfe deinen Transaktionsentwurf. Es wird eine teilsignierte Bitcoin Transaktion (PSBT) erzeugt, die du kopieren und dann mit z.B. einem Offline %1 Wallet oder einem PSBT-kompatiblen Hardware Wallet signieren kannst.</translation> + <source>Create Unsigned</source> + <translation>Unsigniert erstellen</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Speichere Transaktionsdaten</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Teilsignierte Transaktion (Binärdatei) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT gespeichert</translation> </message> <message> <source>or</source> @@ -2409,18 +2594,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Bestätige Transaktionsentwurf</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>PSBT kopieren</translation> - </message> - <message> <source>Send</source> <translation>Senden</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT kopiert</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Nur-Anzeige Saldo:</translation> </message> @@ -3202,12 +3379,28 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Wenn Sie die Wallet zu lange schließen, kann es dazu kommen, dass Sie die gesamte Chain neu synchronisieren müssen, wenn Pruning aktiviert ist.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Schließe alle Wallets</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Sicher, dass Sie alle Wallets schließen möchten?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Es wurde keine Wallet geladen.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Es wurde keine Brieftasche geladen. +Gehen Sie zu Datei > Öffnen Sie die Brieftasche, um eine Brieftasche zu laden. +- ODER-</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Neue Wallet erstellen</translation> </message> </context> <context> @@ -3280,6 +3473,30 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Daten der aktuellen Ansicht in eine Datei exportieren</translation> </message> <message> + <source>Error</source> + <translation>Fehler</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Konnte PSBT aus Zwischenablage nicht entschlüsseln (ungültiges Base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Lade Transaktionsdaten</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Teilsignierte Transaktion (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PSBT-Datei muss kleiner als 100 MiB sein</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>PSBT konnte nicht entschlüsselt werden</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Wallet sichern</translation> </message> @@ -3323,10 +3540,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Prune (Kürzung): Die letzte Synchronisation der Wallet liegt vor gekürzten (gelöschten) Blöcken. Es ist ein -reindex (erneuter Download der gesamten Blockchain im Fall eines gekürzten Knotens) notwendig.</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Fehler: Ein schwerer interner Fehler ist aufgetreten, siehe debug.log für Details.</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Kürze Block-Speicher...</translation> </message> @@ -3339,11 +3552,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Die %s-Entwickler</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Kann keinen Schlüssel für die Wechselgeld-Adresse generieren. Keine Schlüssel im internen Keypool und kann keine Schlüssel generieren. -</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Datenverzeichnis %s kann nicht gesperrt werden. Evtl. wurde %s bereits gestartet.</translation> </message> @@ -3364,6 +3572,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Wenn sie %s nützlich finden, sind Helfer sehr gern gesehen. Besuchen Sie %s um mehr über das Softwareprojekt zu erfahren.</translation> </message> <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>SQLiteDatabase: Konnte das Statement zum Abholen der Anwendungs-ID %s nicht vorbereiten.</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>Die Block-Datenbank enthält einen Block, der in der Zukunft auftaucht. Dies kann daran liegen, dass die Systemzeit Ihres Computers falsch eingestellt ist. Stellen Sie die Block-Datenbank nur wieder her, wenn Sie sich sicher sind, dass Ihre Systemzeit korrekt eingestellt ist.</translation> </message> @@ -3392,14 +3604,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Warnung: Wir scheinen nicht vollständig mit unseren Gegenstellen übereinzustimmen! Sie oder die anderen Knoten müssen unter Umständen Ihre Client-Software aktualisieren.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d der letzten 100 Blöcke haben eine unerwartete Version</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s beschädigt, Datenrettung fehlgeschlagen</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool muss mindestens %d MB betragen</translation> </message> @@ -3477,6 +3681,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Fehler: Wallet konnte während der Initialisierung nicht erneut gescannt werden.</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Verifizierung der Datenbank fehlgeschlagen</translation> + </message> + <message> <source>Importing...</source> <translation>Importiere...</translation> </message> @@ -3505,6 +3713,15 @@ 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>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>Datenbank konnte nicht gelesen werden +Verifikations-Error: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase: Unerwartete Anwendungs-ID. %u statt %u erhalten.</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation>Angegebener Blöcke-Ordner "%s" existiert nicht.</translation> </message> @@ -3525,10 +3742,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Lade P2P-Adressen...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Fehler: Zu wenig freier Speicherplatz auf dem Datenträger!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Lade Sperrliste...</translation> </message> @@ -3593,6 +3806,14 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Fehler: Abhören nach eingehenden Verbindungen fehlgeschlagen (listen meldete Fehler %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s korrupt. Versuche mit dem Wallet-Werkzeug bitcoin-wallet zu retten, oder eine Sicherung wiederherzustellen.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Ein Upgrade auf eine Nicht-HD-Split-Brieftasche ist nicht möglich, ohne ein Upgrade zur Unterstützung des Pre-Split-Keypools durchzuführen. Verwenden Sie bitte die Version 169900 oder keine angegebene Version.</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>Ungültiger Betrag für -maxtxfee=<amount>: '%s' (muss mindestens die minimale Weiterleitungsgebühr in Höhe von %s sein, um zu verhindern dass Transaktionen nicht bearbeitet werden)</translation> </message> @@ -3601,10 +3822,34 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Der Transaktionsbetrag ist zu klein, um ihn nach Abzug der Gebühr zu senden.</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Dieser Fehler kann auftreten, wenn diese Brieftasche nicht ordnungsgemäß heruntergefahren und zuletzt mithilfe eines Builds mit einer neueren Version von Berkeley DB geladen wurde. Verwenden Sie in diesem Fall die Software, die diese Brieftasche zuletzt geladen hat</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Dies ist die maximale Transaktionsgebühr, die Sie (zusätzlich zur normalen Gebühr) zahlen, um die teilweise Vermeidung von Ausgaben gegenüber der regulären Münzauswahl zu priorisieren.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Transaktion erfordert eine Wechselgeldadresse, die jedoch nicht erzeugt werden kann. Bitte zunächst keypoolrefill aufrufen.</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>Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um zum ungekürzten Modus zurückzukehren. Dies erfordert, dass die gesamte Blockchain erneut heruntergeladen wird.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Ein fataler interner Fehler ist aufgetreten, siehe debug.log für Details</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Kann -peerblockfilters nicht ohne -blockfilterindex setzen.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Freier Plattenspeicher zu gering!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Fehler beim Lesen der Datenbank, Ausführung wird beendet.</translation> </message> @@ -3617,6 +3862,14 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Fehler: Zu wenig Speicherplatz auf der Festplatte %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Fehler: Schlüsselspeicher ausgeschöpft, bitte zunächst keypoolrefill ausführen</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Der Gebührensatz (%s) ist niedriger als die Mindestgebührensatz (%s) Einstellung.</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Ungültige Onion-Adresse oder ungültiger Hostname: '%s'</translation> </message> @@ -3637,6 +3890,10 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Angabe eines Ports benötigt für -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Kein Proxy-Server angegeben. Nutze -proxy=<ip> oder -proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Kürzungsmodus ist nicht mit -blockfilterindex kompatibel.</translation> </message> @@ -3711,10 +3968,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Warnung: Unbekannte neue Regeln aktiviert (Versionsbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Lösche alle Transaktionen aus Wallet...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee ist auf einen sehr hohen Wert festgelegt! Gebühren dieser Höhe könnten für eine einzelne Transaktion bezahlt werden.</translation> </message> @@ -3727,10 +3980,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Gesamtlänge des Netzwerkversionstrings (%i) erreicht die maximale Länge (%i). Reduzieren Sie die Nummer oder die Größe von uacomments.</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>Warnung: wallet.dat beschädigt, Datenrettung erfolgreich! Original %s wurde als wallet %s in %s gespeichert. Falls Ihr Kontostand oder Transaktionen nicht korrekt sind, sollten Sie von einer Datensicherung wiederherstellen.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s wurde sehr hoch eingestellt!</translation> </message> @@ -3775,10 +4024,6 @@ Hinweis: Eine Gebühr von "100 Satoshis pro kB" bei einer Größe der Transaktio <translation>Unzureichender Kontostand</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>Ein Wallet das kein geteiltes HD-Wallet ist, kann kein Upgrade erfahren, wenn nicht auch der Schlüsselpool vor der Teilung ein Upgrade erfahren hat. Bitte benutzen Sie upgradewallet=169900 oder -upgradewallet ohne Angabe einer Version.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Die Gebührenabschätzung schlug fehl. Fallbackfee ist deaktiviert. Warten Sie ein paar Blöcke oder aktivieren Sie -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_el.ts b/src/qt/locale/bitcoin_el.ts index d903e2f85d..e9c08feaee 100644 --- a/src/qt/locale/bitcoin_el.ts +++ b/src/qt/locale/bitcoin_el.ts @@ -70,10 +70,6 @@ <translation>Αυτές είναι οι Bitcoin διευθύνσεις σας για να στέλνετε πληρωμές. Να ελέγχετε πάντα το ποσό, καθώς και τη διεύθυνση παραλήπτη πριν στείλετε νομίσματα.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Αυτές είναι οι Bitcoin διευθύνσεις για την λήψη πληρωμών. Χρησιμοποιήσε το κουμπί 'Δημιουργία νέας διεύθυνσης λήψεων' στο παράθυρο λήψεων για την δημιουργία νέας διεύθυνσης </translation> - </message> - <message> <source>&Copy Address</source> <translation>&Αντιγραφή Διεύθυνσης</translation> </message> @@ -629,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Το πορτοφόλι είναι <b>κρυπτογραφημένο</b> και <b>κλειδωμένο</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Εμφανίστηκε ένα μοιραίο σφάλμα. Το Bitcoin δεν μπορεί πλέον να συνεχίσει με ασφάλεια και θα σταματήσει.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -1131,10 +1123,6 @@ <translation>Εμφανίζει αν ο προεπιλεγμένος διακομιστής μεσολάβησης SOCKS5 χρησιμοποιείται για την προσέγγιση χρηστών μέσω αυτού του τύπου δικτύου.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Χρησιμοποιήστε χωριστό SOCKS&5 proxy για να προσεγγίσετε συνομηλίκους μέσω κρυφών υπηρεσιών Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Απόκρυψη του εικονιδίου από το συρτάρι του συστήματος.</translation> </message> @@ -1267,10 +1255,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Συνδεθείτε στο δίκτυο Bitcoin μέσω ενός ξεχωριστού διακομιστή μεσολάβησης SOCKS5 για κρυφές υπηρεσίες Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Παράθυρο</translation> </message> @@ -1442,7 +1426,34 @@ <source>Current total balance in watch-only addresses</source> <translation>Το τρέχον συνολικό υπόλοιπο σε διευθύνσεις παρακολούθησης μόνο</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Διάλογος</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Αντιγραφή στο Πρόχειρο</translation> + </message> + <message> + <source>Save...</source> + <translation>Αποθήκευση...</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Αποθήκευση Δεδομένων Συναλλαγής</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Συνολικό Ποσό</translation> + </message> + <message> + <source>or</source> + <translation>ή</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1702,10 +1713,6 @@ <translation>Αλυσίδα μπλοκ</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Τρέχον αριθμός μπλοκ</translation> - </message> - <message> <source>Memory Pool</source> <translation>Πισίνα μνήμης</translation> </message> @@ -1750,10 +1757,6 @@ <translation>Επιλέξτε ένα χρήστη για να δείτε αναλυτικές πληροφορίες.</translation> </message> <message> - <source>Whitelisted</source> - <translation> Τα στοιχεία που έχουν πρόσβαση στο σύστημα</translation> - </message> - <message> <source>Direction</source> <translation>Κατεύθυνση</translation> </message> @@ -1774,6 +1777,14 @@ <translation>Συγχρονισμένα Μπλοκς</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Το χαρτογραφημένο Αυτόνομο Σύστημα που χρησιμοποιείται για τη διαφοροποίηση της επιλογής ομοτίμων.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Χαρτογραφημένο ως</translation> + </message> + <message> <source>User Agent</source> <translation>Agent χρήστη</translation> </message> @@ -1798,10 +1809,6 @@ <translation>Υπηρεσίες</translation> </message> <message> - <source>Ban Score</source> - <translation>Σκορ Aποκλεισμού</translation> - </message> - <message> <source>Connection Time</source> <translation>Χρόνος σύνδεσης</translation> </message> @@ -1951,14 +1958,6 @@ <translation>Εξερχόμενα</translation> </message> <message> - <source>Yes</source> - <translation>Ναι</translation> - </message> - <message> - <source>No</source> - <translation>Όχι</translation> - </message> - <message> <source>Unknown</source> <translation>Άγνωστο(α)</translation> </message> @@ -2057,12 +2056,24 @@ <source>Copy amount</source> <translation>Αντιγραφή ποσού</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Δεν είναι δυνατό το ξεκλείδωμα του πορτοφολιού.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Κώδικας QR</translation> + <source>Amount:</source> + <translation>Ποσό:</translation> + </message> + <message> + <source>Message:</source> + <translation>Μήνυμα:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Πορτοφόλι</translation> </message> <message> <source>Copy &URI</source> @@ -2084,30 +2095,6 @@ <source>Payment information</source> <translation>Πληροφορίες πληρωμής</translation> </message> - <message> - <source>URI</source> - <translation>URI</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> </context> <context> <name>RecentRequestsTableModel</name> @@ -2352,8 +2339,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Είστε βέβαιοι ότι θέλετε να στείλετε;</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Παρακαλώ ελέγξτε την πρόταση συναλλαγής. Αυτό θα παράγει μια συναλλαγή Bitcoin με μερική υπογραφή (PSBT), την οποία μπορείτε να αντιγράψετε και στη συνέχεια να υπογράψετε με π.χ. ένα πορτοφόλι %1 εκτός σύνδεσης ή ένα πορτοφόλι υλικού συμβατό με το PSBT.</translation> + <source>Save Transaction Data</source> + <translation>Αποθήκευση Δεδομένων Συναλλαγής</translation> </message> <message> <source>or</source> @@ -2393,18 +2380,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation> Επιβεβαιώστε την πρόταση συναλλαγής</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Αντιγράψτε το PSBT στο πρόχειρο</translation> - </message> - <message> <source>Send</source> <translation>Αποστολή</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT αντιγράφηκε</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Παρακολούθηση μόνο ισορροπίας:</translation> </message> @@ -3182,12 +3161,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Το κλείσιμο του πορτοφολιού για πολύ μεγάλο χρονικό διάστημα μπορεί να οδηγήσει στην επανασύνδεση ολόκληρης της αλυσίδας αν είναι ενεργοποιημένη η περικοπή.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Δεν έχει φορτωθεί πορτοφόλι.</translation> + <source>Create a new wallet</source> + <translation>Δημιουργία νέου Πορτοφολιού</translation> </message> </context> <context> @@ -3260,6 +3239,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Εξαγωγή δεδομένων καρτέλας σε αρχείο</translation> </message> <message> + <source>Error</source> + <translation>Σφάλμα</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Αντίγραφο ασφαλείας Πορτοφολιού</translation> </message> @@ -3303,10 +3286,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Κλάδεμα: ο τελευταίος συγχρονισμός πορτοφολιού ξεπερνά τα κλαδεμένα δεδομένα. Πρέπει να κάνετε -reindex (κατεβάστε ολόκληρο το blockchain και πάλι σε περίπτωση κλαδέματος κόμβου)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Σφάλμα: Παρουσιάστηκε θανάσιμο εσωτερικό σφάλμα, ανατρέξτε στην ενότητα debug.log για λεπτομέρειες</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Κλάδεμα blockstore...</translation> </message> @@ -3319,10 +3298,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Οι προγραμματιστές %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Δεν είναι δυνατή η δημιουργία ενός κλειδιού αλλαγής διεύθυνσης. Δεν υπάρχουν κλειδιά στην εσωτερική κεντρική μονάδα κλειδιών και δεν μπορούν να δημιουργήσουν κανένα κλειδί.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Δεν είναι δυνατή η λήψη κλειδώματος στον κατάλογο δεδομένων %s. Το %s πιθανώς ήδη εκτελείται.</translation> </message> @@ -3371,14 +3346,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Προειδοποίηση: Δεν φαίνεται να συμφωνούμε πλήρως με τους συμμαθητές μας! Ίσως χρειαστεί να κάνετε αναβάθμιση ή ίσως χρειαστεί να αναβαθμίσετε άλλους κόμβους.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>Το %d των τελευταίων 100 μπλοκ έχει μη αναμενόμενη έκδοση</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s διεφθαρμένη, αποτυχία διάσωσης</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool πρέπει να είναι τουλάχιστον %d MB</translation> </message> @@ -3495,10 +3462,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Φόρτωση P2P διευθύνσεων...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation> Σφάλμα: Ο χώρος στο δίσκο είναι πολύ χαμηλός!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Φόρτωση λίστα απαγόρευσης...</translation> </message> @@ -3681,10 +3644,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Προειδοποίηση: Άγνωστοι νέοι κανόνες ενεργοποιήθηκαν (έκδοσηbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Μεταφορά όλων των συναλλαγών από το πορτοφόλι</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation> -maxtxfee είναι καταχωρημένο πολύ υψηλά! Έξοδα τόσο υψηλά μπορούν να πληρωθούν σε μια ενιαία συναλλαγή.</translation> </message> @@ -3729,10 +3688,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Ανεπαρκές κεφάλαιο</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>Δεν είναι δυνατή η αναβάθμιση ενός διαχωρισμένου πορτοφολιού χωρίς HD χωρίς αναβάθμιση για να υποστηρίξετε τη διαχωριστική κλειδαριά. Παρακαλούμε χρησιμοποιήστε το -upgradewallet = 169900 ή -upgradewallet χωρίς να έχετε καθορίσει καμία έκδοση.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Η αποτίμηση του τέλους απέτυχε. Το Fallbackfee είναι απενεργοποιημένο. Περιμένετε λίγα τετράγωνα ή ενεργοποιήστε το -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 6b4174f313..c55cc65b63 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -90,7 +90,8 @@ </message> <message> <location line="+5"/> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> @@ -109,7 +110,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+177"/> + <location line="+179"/> <source>Export Address List</source> <translation type="unfinished"></translation> </message> @@ -132,7 +133,7 @@ <context> <name>AddressTableModel</name> <message> - <location filename="../addresstablemodel.cpp" line="+165"/> + <location filename="../addresstablemodel.cpp" line="+168"/> <source>Label</source> <translation type="unfinished"></translation> </message> @@ -175,7 +176,7 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../askpassphrasedialog.cpp" line="+50"/> + <location filename="../askpassphrasedialog.cpp" line="+51"/> <source>Encrypt wallet</source> <translation type="unfinished"></translation> </message> @@ -205,7 +206,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+46"/> + <location line="+48"/> <source>Confirm wallet encryption</source> <translation type="unfinished"></translation> </message> @@ -226,7 +227,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-145"/> + <location line="-147"/> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> <translation type="unfinished"></translation> </message> @@ -236,7 +237,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+53"/> + <location line="+55"/> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation type="unfinished"></translation> </message> @@ -325,17 +326,17 @@ <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+316"/> + <location filename="../bitcoingui.cpp" line="+322"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+630"/> + <location line="+669"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-708"/> + <location line="-747"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -410,7 +411,7 @@ <translation>&Change Passphrase...</translation> </message> <message> - <location line="+18"/> + <location line="+22"/> <source>Open &URI...</source> <translation type="unfinished"></translation> </message> @@ -425,12 +426,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+191"/> + <location line="+210"/> <source>Wallet:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+339"/> + <location line="+351"/> <source>Click to disable network activity.</source> <translation type="unfinished"></translation> </message> @@ -450,17 +451,17 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+53"/> + <location line="+57"/> <source>Reindexing blocks on disk...</source> <translation>Reindexing blocks on disk...</translation> </message> <message> - <location line="+317"/> + <location line="+315"/> <source>Proxy is <b>enabled</b>: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1028"/> + <location line="-1065"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -515,17 +516,17 @@ <translation>Verify messages to ensure they were signed with specified Bitcoin addresses</translation> </message> <message> - <location line="+111"/> + <location line="+129"/> <source>&File</source> <translation>&File</translation> </message> <message> - <location line="+15"/> + <location line="+18"/> <source>&Settings</source> <translation>&Settings</translation> </message> <message> - <location line="+59"/> + <location line="+61"/> <source>&Help</source> <translation>&Help</translation> </message> @@ -535,12 +536,12 @@ <translation>Tabs toolbar</translation> </message> <message> - <location line="-258"/> + <location line="-281"/> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+71"/> + <location line="+75"/> <source>Show the list of used sending addresses and labels</source> <translation type="unfinished"></translation> </message> @@ -550,12 +551,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+17"/> + <location line="+20"/> <source>&Command-line options</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+528"/> + <location line="+556"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -563,7 +564,7 @@ </translation> </message> <message> - <location line="+76"/> + <location line="+80"/> <source>Indexing blocks on disk...</source> <translation type="unfinished"></translation> </message> @@ -596,7 +597,7 @@ <translation>Transactions after this will not yet be visible.</translation> </message> <message> - <location line="+28"/> + <location line="+25"/> <source>Error</source> <translation>Error</translation> </message> @@ -611,12 +612,32 @@ <translation>Information</translation> </message> <message> - <location line="-81"/> + <location line="-78"/> <source>Up to date</source> <translation>Up to date</translation> </message> <message> - <location line="-655"/> + <location line="-695"/> + <source>&Load PSBT from file...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Load PSBT from clipboard...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> <source>Node window</source> <translation type="unfinished"></translation> </message> @@ -661,12 +682,32 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+6"/> + <source>Close All Wallets...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Close all wallets</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> <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="+29"/> + <location line="+2"/> + <source>&Mask values</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Mask the values in the Overview tab</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+32"/> <source>default wallet</source> <translation type="unfinished"></translation> </message> @@ -676,7 +717,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+55"/> + <location line="+64"/> <source>&Window</source> <translation type="unfinished">&Window</translation> </message> @@ -696,12 +737,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+238"/> + <location line="+246"/> <source>%1 client</source> <translation type="unfinished"></translation> </message> <message> - <location line="+241"/> + <location line="+249"/> <source>Connecting to peers...</source> <translation type="unfinished"></translation> </message> @@ -711,7 +752,7 @@ <translation>Catching up...</translation> </message> <message> - <location line="+50"/> + <location line="+47"/> <source>Error: %1</source> <translation type="unfinished"></translation> </message> @@ -721,7 +762,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+99"/> + <location line="+100"/> <source>Date: %1 </source> <translation type="unfinished"></translation> @@ -792,8 +833,13 @@ <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+384"/> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> + <location line="+129"/> + <source>Original message:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../bitcoin.cpp" line="+418"/> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> <translation type="unfinished"></translation> </message> </context> @@ -885,7 +931,7 @@ <translation type="unfinished">Confirmed</translation> </message> <message> - <location filename="../coincontroldialog.cpp" line="+53"/> + <location filename="../coincontroldialog.cpp" line="+54"/> <source>Copy address</source> <translation type="unfinished"></translation> </message> @@ -946,12 +992,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+313"/> + <location line="+302"/> <source>(%1 locked)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+157"/> + <location line="+155"/> <source>yes</source> <translation type="unfinished"></translation> </message> @@ -971,7 +1017,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+45"/> + <location line="+38"/> <location line="+54"/> <source>(no label)</source> <translation type="unfinished"></translation> @@ -990,12 +1036,12 @@ <context> <name>CreateWalletActivity</name> <message> - <location filename="../walletcontroller.cpp" line="+209"/> + <location filename="../walletcontroller.cpp" line="+241"/> <source>Creating Wallet <b>%1</b>...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+26"/> + <location line="+28"/> <source>Create wallet failed</source> <translation type="unfinished"></translation> </message> @@ -1048,10 +1094,25 @@ <translation type="unfinished"></translation> </message> <message> + <location line="+13"/> + <source>Use descriptors for scriptPubKey management</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Descriptor Wallet</source> + <translation type="unfinished"></translation> + </message> + <message> <location filename="../createwalletdialog.cpp" line="+19"/> <source>Create</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+20"/> + <source>Compiled without sqlite support (required for descriptor wallets)</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>EditAddressDialog</name> @@ -1096,7 +1157,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+75"/> + <location line="+77"/> <source>The entered address "%1" is not a valid Bitcoin address.</source> <translation type="unfinished"></translation> </message> @@ -1124,7 +1185,7 @@ <context> <name>FreespaceChecker</name> <message> - <location filename="../intro.cpp" line="+71"/> + <location filename="../intro.cpp" line="+72"/> <source>A new data directory will be created.</source> <translation>A new data directory will be created.</translation> </message> @@ -1152,7 +1213,7 @@ <context> <name>HelpMessageDialog</name> <message> - <location filename="../utilitydialog.cpp" line="+35"/> + <location filename="../utilitydialog.cpp" line="+37"/> <source>version</source> <translation type="unfinished">version</translation> </message> @@ -1304,7 +1365,7 @@ <message> <location line="+7"/> <location line="+26"/> - <location filename="../modaloverlay.cpp" line="+145"/> + <location filename="../modaloverlay.cpp" line="+153"/> <source>Unknown...</source> <translation type="unfinished"></translation> </message> @@ -1345,12 +1406,12 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../modaloverlay.cpp" line="-111"/> + <location filename="../modaloverlay.cpp" line="-119"/> <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+117"/> + <location line="+125"/> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation type="unfinished"></translation> </message> @@ -1437,12 +1498,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+38"/> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+108"/> + <location line="+146"/> <source>Hide the icon from the system tray.</source> <translation type="unfinished"></translation> </message> @@ -1611,12 +1667,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+105"/> + <location line="+130"/> <source>&Window</source> <translation>&Window</translation> </message> @@ -1666,7 +1717,17 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+464"/> + <location line="+250"/> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+211"/> <source>&Third party transaction URLs</source> <translation type="unfinished"></translation> </message> @@ -1691,7 +1752,7 @@ <translation>default</translation> </message> <message> - <location line="+65"/> + <location line="+67"/> <source>none</source> <translation type="unfinished"></translation> </message> @@ -1751,12 +1812,12 @@ </message> <message> <location line="+62"/> - <location line="+386"/> + <location line="+394"/> <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>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.</translation> </message> <message> - <location line="-139"/> + <location line="-141"/> <source>Watch-only:</source> <translation type="unfinished"></translation> </message> @@ -1766,22 +1827,22 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+16"/> + <location line="+17"/> <source>Your current spendable balance</source> <translation>Your current spendable balance</translation> </message> <message> - <location line="+41"/> + <location line="+42"/> <source>Pending:</source> <translation type="unfinished"></translation> </message> <message> - <location line="-236"/> + <location line="-242"/> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> </message> <message> - <location line="+112"/> + <location line="+114"/> <source>Immature:</source> <translation>Immature:</translation> </message> @@ -1791,22 +1852,22 @@ <translation>Mined balance that has not yet matured</translation> </message> <message> - <location line="-177"/> + <location line="-181"/> <source>Balances</source> <translation type="unfinished"></translation> </message> <message> - <location line="+161"/> + <location line="+164"/> <source>Total:</source> <translation>Total:</translation> </message> <message> - <location line="+61"/> + <location line="+63"/> <source>Your current total balance</source> <translation>Your current total balance</translation> </message> <message> - <location line="+92"/> + <location line="+95"/> <source>Your current balance in watch-only addresses</source> <translation type="unfinished"></translation> </message> @@ -1821,20 +1882,178 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-317"/> + <location line="-324"/> <source>Unconfirmed transactions to watch-only addresses</source> <translation type="unfinished"></translation> </message> <message> - <location line="+50"/> + <location line="+52"/> <source>Mined balance in watch-only addresses that has not yet matured</source> <translation type="unfinished"></translation> </message> <message> - <location line="+128"/> + <location line="+131"/> <source>Current total balance in watch-only addresses</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../overviewpage.cpp" line="+166"/> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <location filename="../forms/psbtoperationsdialog.ui" line="+14"/> + <source>Dialog</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+72"/> + <source>Sign Tx</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <source>Broadcast Tx</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+20"/> + <source>Copy to Clipboard</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Save...</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../psbtoperationsdialog.cpp" line="+55"/> + <source>Failed to load transaction: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+18"/> + <source>Failed to sign transaction: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Could not sign any more inputs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Unknown error processing transaction.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Transaction broadcast failed: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> + <source>PSBT copied to clipboard.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>Save Transaction Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>PSBT saved to disk.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> + <source> * Sends %1 to %2</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Pays transaction fee: </source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> + <source>Total Amount</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>or</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Transaction has %1 unsigned inputs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+42"/> + <source>Transaction is missing some information about inputs.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Transaction still needs signature(s).</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>(But this wallet cannot sign transactions.)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>(But this wallet does not have the right keys.)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Transaction status is unknown.</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1931,17 +2150,17 @@ <context> <name>QObject</name> <message> - <location filename="../bitcoinunits.cpp" line="+195"/> + <location filename="../bitcoinunits.cpp" line="+209"/> <source>Amount</source> <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+111"/> + <location filename="../guiutil.cpp" line="+108"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+618"/> + <location line="+652"/> <source>%1 d</source> <translation type="unfinished"></translation> </message> @@ -1957,7 +2176,7 @@ </message> <message> <location line="+2"/> - <location line="+48"/> + <location line="+26"/> <source>%1 s</source> <translation type="unfinished"></translation> </message> @@ -2051,7 +2270,7 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+114"/> + <location filename="../bitcoin.cpp" line="+105"/> <source>Error: Specified data directory "%1" does not exist.</source> <translation type="unfinished"></translation> </message> @@ -2066,7 +2285,12 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+65"/> + <location line="+9"/> + <source>Error initializing settings: %1</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+63"/> <source>%1 didn't yet exit safely...</source> <translation type="unfinished"></translation> </message> @@ -2079,7 +2303,7 @@ <context> <name>QRImageWidget</name> <message> - <location filename="../qrimagewidget.cpp" line="+29"/> + <location filename="../qrimagewidget.cpp" line="+30"/> <source>&Save Image...</source> <translation type="unfinished"></translation> </message> @@ -2099,7 +2323,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+39"/> + <location line="+41"/> <source>QR code support not available.</source> <translation type="unfinished"></translation> </message> @@ -2129,8 +2353,7 @@ <location line="+23"/> <location line="+36"/> <location line="+23"/> - <location line="+716"/> - <location line="+23"/> + <location line="+710"/> <location line="+23"/> <location line="+23"/> <location line="+23"/> @@ -2148,12 +2371,13 @@ <location line="+23"/> <location line="+23"/> <location line="+26"/> - <location filename="../rpcconsole.cpp" line="+1121"/> + <location filename="../rpcconsole.cpp" line="+1127"/> + <location line="+8"/> <source>N/A</source> <translation>N/A</translation> </message> <message> - <location line="-1456"/> + <location line="-1427"/> <source>Client version</source> <translation>Client version</translation> </message> @@ -2218,12 +2442,7 @@ <translation>Block chain</translation> </message> <message> - <location line="+7"/> - <source>Current number of blocks</source> - <translation>Current number of blocks</translation> - </message> - <message> - <location line="+52"/> + <location line="+59"/> <source>Memory Pool</source> <translation type="unfinished"></translation> </message> @@ -2254,18 +2473,18 @@ </message> <message> <location line="+80"/> - <location line="+589"/> + <location line="+560"/> <source>Received</source> <translation type="unfinished"></translation> </message> <message> - <location line="-509"/> - <location line="+486"/> + <location line="-480"/> + <location line="+457"/> <source>Sent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-445"/> + <location line="-416"/> <source>&Peers</source> <translation type="unfinished"></translation> </message> @@ -2276,18 +2495,13 @@ </message> <message> <location line="+65"/> - <location filename="../rpcconsole.cpp" line="-624"/> - <location line="+756"/> + <location filename="../rpcconsole.cpp" line="-637"/> + <location line="+766"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+37"/> - <source>Whitelisted</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+23"/> + <location line="+54"/> <source>Direction</source> <translation type="unfinished"></translation> </message> @@ -2312,7 +2526,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+256"/> + <location line="+233"/> <source>The mapped Autonomous System used for diversifying peer selection.</source> <translation type="unfinished"></translation> </message> @@ -2322,18 +2536,23 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-1423"/> - <location line="+1072"/> + <location line="-1394"/> + <location line="+1066"/> <source>User Agent</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1146"/> + <location line="-1140"/> <source>Node window</source> <translation type="unfinished"></translation> </message> <message> - <location line="+409"/> + <location line="+279"/> + <source>Current block height</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+130"/> <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> @@ -2348,17 +2567,17 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+644"/> - <source>Services</source> + <location line="+546"/> + <source>Permissions</source> <translation type="unfinished"></translation> </message> <message> <location line="+92"/> - <source>Ban Score</source> + <source>Services</source> <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> + <location line="+92"/> <source>Connection Time</source> <translation type="unfinished"></translation> </message> @@ -2398,7 +2617,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="-1169"/> + <location line="-1140"/> <source>Last block time</source> <translation>Last block time</translation> </message> @@ -2423,7 +2642,7 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-408"/> + <location filename="../rpcconsole.cpp" line="-416"/> <source>In:</source> <translation type="unfinished"></translation> </message> @@ -2521,7 +2740,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+189"/> + <location line="+192"/> <source>(node id: %1)</source> <translation type="unfinished"></translation> </message> @@ -2547,17 +2766,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Yes</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+0"/> - <source>No</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+13"/> + <location line="+20"/> <location line="+6"/> <source>Unknown</source> <translation type="unfinished"></translation> @@ -2597,12 +2806,12 @@ </message> <message> <location line="-39"/> - <location line="+153"/> + <location line="+159"/> <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-121"/> + <location line="-127"/> <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> <translation type="unfinished"></translation> </message> @@ -2617,7 +2826,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+17"/> + <location line="+23"/> <source>Clear all fields of the form.</source> <translation type="unfinished"></translation> </message> @@ -2681,68 +2890,73 @@ <source>Copy amount</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+131"/> + <source>Could not unlock wallet.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Could not generate new %1 address</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <location filename="../forms/receiverequestdialog.ui" line="+29"/> - <source>QR Code</source> + <location filename="../forms/receiverequestdialog.ui" line="+14"/> + <source>Request payment to ...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+46"/> - <source>Copy &URI</source> + <location line="+76"/> + <source>Address:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> - <source>Copy &Address</source> + <location line="+29"/> + <source>Amount:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> - <source>&Save Image...</source> + <location line="+29"/> + <source>Label:</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../receiverequestdialog.cpp" line="+64"/> - <source>Request payment to %1</source> + <location line="+32"/> + <source>Message:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> - <source>Payment information</source> + <location line="+32"/> + <source>Wallet:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> - <source>URI</source> + <location line="+28"/> + <source>Copy &URI</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Address</source> + <location line="+10"/> + <source>Copy &Address</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Amount</source> - <translation type="unfinished">Amount</translation> - </message> - <message> - <location line="+2"/> - <source>Label</source> + <location line="+10"/> + <source>&Save Image...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Message</source> + <location filename="../receiverequestdialog.cpp" line="+49"/> + <source>Request payment to %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Wallet</source> - <translation type="unfinished">Wallet</translation> + <location filename="../forms/receiverequestdialog.ui" line="-221"/> + <source>Payment information</source> + <translation type="unfinished"></translation> </message> </context> <context> @@ -2787,7 +3001,7 @@ <name>SendCoinsDialog</name> <message> <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+622"/> + <location filename="../sendcoinsdialog.cpp" line="+664"/> <source>Send Coins</source> <translation>Send Coins</translation> </message> @@ -2974,7 +3188,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="-533"/> + <location filename="../sendcoinsdialog.cpp" line="-572"/> <source>Copy quantity</source> <translation type="unfinished"></translation> </message> @@ -3024,7 +3238,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="+100"/> + <location line="+90"/> <source> from wallet '%1'</source> <translation type="unfinished"></translation> </message> @@ -3039,7 +3253,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="+8"/> + <location line="+7"/> <source>Do you want to draft this transaction?</source> <translation type="unfinished"></translation> </message> @@ -3049,12 +3263,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="+5"/> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <location line="+71"/> + <source>Create Unsigned</source> <translation type="unfinished"></translation> </message> <message> - <location line="+43"/> + <location line="+44"/> + <source>Save Transaction Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>PSBT saved</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-75"/> <source>or</source> <translation type="unfinished"></translation> </message> @@ -3064,7 +3293,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="-22"/> + <location line="-24"/> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> <source>Please, review your transaction.</source> <translation type="unfinished"></translation> </message> @@ -3084,12 +3318,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="+9"/> + <location line="+7"/> <source>To review recipient list click "Show Details..."</source> <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> + <location line="+18"/> <source>Confirm send coins</source> <translation type="unfinished"></translation> </message> @@ -3100,21 +3334,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+1"/> - <source>Copy PSBT to clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+0"/> <source>Send</source> <translation type="unfinished"></translation> </message> <message> - <location line="+23"/> - <source>PSBT copied</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+166"/> + <location line="+228"/> <source>Watch-only balance:</source> <translation type="unfinished"></translation> </message> @@ -3159,7 +3383,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+125"/> + <location line="+124"/> <source>Estimated to begin confirmation within %n block(s).</source> <translation> <numerusform>Estimated to begin confirmation within %n block.</numerusform> @@ -3167,7 +3391,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </translation> </message> <message> - <location line="+101"/> + <location line="+100"/> <source>Warning: Invalid Bitcoin address</source> <translation type="unfinished"></translation> </message> @@ -3305,7 +3529,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>ShutdownWindow</name> <message> - <location filename="../utilitydialog.cpp" line="+83"/> + <location filename="../utilitydialog.cpp" line="+85"/> <source>%1 is shutting down...</source> <translation type="unfinished"></translation> </message> @@ -3444,7 +3668,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="../signverifymessagedialog.cpp" line="+117"/> + <location filename="../signverifymessagedialog.cpp" line="+120"/> <location line="+99"/> <source>The entered address is invalid.</source> <translation type="unfinished"></translation> @@ -3518,7 +3742,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>TrafficGraphWidget</name> <message> - <location filename="../trafficgraphwidget.cpp" line="+81"/> + <location filename="../trafficgraphwidget.cpp" line="+82"/> <source>KB/s</source> <translation type="unfinished"></translation> </message> @@ -3764,7 +3988,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>This pane shows a detailed description of the transaction</translation> </message> <message> - <location filename="../transactiondescdialog.cpp" line="+17"/> + <location filename="../transactiondescdialog.cpp" line="+18"/> <source>Details for %1</source> <translation type="unfinished"></translation> </message> @@ -3772,7 +3996,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="+225"/> + <location filename="../transactiontablemodel.cpp" line="+251"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -4094,7 +4318,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="+171"/> + <location line="+172"/> <source>Range:</source> <translation type="unfinished"></translation> </message> @@ -4107,7 +4331,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="+156"/> + <location filename="../bitcoingui.cpp" line="+40"/> <source>Unit to show amounts in. Click to select another unit.</source> <translation type="unfinished"></translation> </message> @@ -4115,7 +4339,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>WalletController</name> <message> - <location filename="../walletcontroller.cpp" line="-211"/> + <location filename="../walletcontroller.cpp" line="-238"/> <source>Close wallet</source> <translation type="unfinished"></translation> </message> @@ -4129,24 +4353,41 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+13"/> + <source>Close all wallets</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Are you sure you wish to close all wallets?</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <location filename="../walletframe.cpp" line="+28"/> - <source>No wallet has been loaded.</source> + <location filename="../walletframe.cpp" line="+39"/> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Create a new wallet</source> <translation type="unfinished"></translation> </message> </context> <context> <name>WalletModel</name> <message> - <location filename="../walletmodel.cpp" line="+195"/> + <location filename="../walletmodel.cpp" line="+214"/> <source>Send Coins</source> <translation type="unfinished">Send Coins</translation> </message> <message> - <location line="+288"/> + <location line="+282"/> <location line="+45"/> <location line="+13"/> <location line="+5"/> @@ -4217,7 +4458,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>WalletView</name> <message> - <location filename="../walletview.cpp" line="+46"/> + <location filename="../walletview.cpp" line="+51"/> <source>&Export</source> <translation type="unfinished">&Export</translation> </message> @@ -4227,7 +4468,39 @@ 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="+182"/> + <location line="+165"/> + <location line="+9"/> + <location line="+10"/> + <source>Error</source> + <translation type="unfinished">Error</translation> + </message> + <message> + <location line="-19"/> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Load Transaction Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Partially Signed Transaction (*.psbt)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>PSBT file must be smaller than 100 MiB</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Unable to decode PSBT</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+39"/> <source>Backup Wallet</source> <translation type="unfinished"></translation> </message> @@ -4265,12 +4538,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+28"/> + <location filename="../bitcoinstrings.cpp" line="+27"/> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> <translation type="unfinished"></translation> </message> <message> - <location line="+20"/> + <location line="+23"/> <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> <translation type="unfinished"></translation> </message> @@ -4280,32 +4553,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="+68"/> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+26"/> + <location line="+112"/> <source>Pruning blockstore...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+30"/> + <location line="+36"/> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-162"/> + <location line="-188"/> <source>The %s developers</source> <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> + <location line="+7"/> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation type="unfinished"></translation> </message> @@ -4315,12 +4578,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="+10"/> + <location line="+9"/> <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="+11"/> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <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> @@ -4331,21 +4599,36 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+8"/> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+11"/> <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+6"/> <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+11"/> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> <translation type="unfinished"></translation> </message> @@ -4360,32 +4643,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="+7"/> + <location line="+3"/> <source>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> - <source>%d of last 100 blocks have unexpected version</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> - <source>%s corrupt, salvage failed</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> + <location line="+7"/> <source>-maxmempool must be at least %d MB</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="+3"/> <source>Cannot resolve -%s address: '%s'</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="+3"/> <source>Change index out of range</source> <translation type="unfinished"></translation> </message> @@ -4415,7 +4688,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="+1"/> + <location line="+2"/> <source>Do you want to rebuild the block database now?</source> <translation>Do you want to rebuild the block database now?</translation> </message> @@ -4455,12 +4728,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>Error loading block database</translation> </message> <message> - <location line="+2"/> + <location line="+1"/> <source>Error opening block database</source> <translation>Error opening block database</translation> </message> <message> - <location line="+6"/> + <location line="+5"/> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> </message> @@ -4471,6 +4744,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos </message> <message> <location line="+1"/> + <source>Failed to verify database</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Ignoring duplicate -wallet %s.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Importing...</source> <translation type="unfinished"></translation> </message> @@ -4505,7 +4788,37 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> + <location line="+18"/> + <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> <source>Specified blocks directory "%s" does not exist.</source> <translation type="unfinished"></translation> </message> @@ -4525,22 +4838,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="-46"/> + <location line="-53"/> <source>Loading P2P addresses...</source> <translation type="unfinished"></translation> </message> <message> - <location line="-15"/> - <source>Error: Disk space is too low!</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+16"/> + <location line="+1"/> <source>Loading banlist...</source> <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+5"/> <source>Not enough file descriptors available.</source> <translation>Not enough file descriptors available.</translation> </message> @@ -4565,7 +4873,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="+8"/> + <location line="+14"/> <source>The source code is available from %s.</source> <translation type="unfinished"></translation> </message> @@ -4610,27 +4918,67 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> - <location line="-151"/> + <location line="-178"/> <source>Error: Listening for incoming connections failed (listen returned error %s)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> + <location line="-20"/> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+14"/> <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> <message> - <location line="+19"/> + <location line="+31"/> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation type="unfinished"></translation> </message> <message> - <location line="+31"/> + <location line="+2"/> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+17"/> <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="+27"/> + <location line="+5"/> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+8"/> + <source>Disk space is too low!</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> <source>Error reading from database, shutting down.</source> <translation type="unfinished"></translation> </message> @@ -4640,12 +4988,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="+2"/> + <location line="+1"/> <source>Error: Disk space is low for %s</source> <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+1"/> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> <source>Invalid -onion address or hostname: '%s'</source> <translation type="unfinished"></translation> </message> @@ -4670,6 +5028,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation type="unfinished"></translation> </message> <message> + <location line="+1"/> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation type="unfinished"></translation> + </message> + <message> <location line="+3"/> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation type="unfinished"></translation> @@ -4680,7 +5043,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="+4"/> + <location line="+10"/> <source>Section [%s] is not recognized.</source> <translation type="unfinished"></translation> </message> @@ -4761,17 +5124,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="+1"/> - <source>Zapping all transactions from wallet...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="-174"/> + <location line="-196"/> <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="+53"/> + <location line="+68"/> <source>This is the transaction fee you may pay when fee estimates are not available.</source> <translation type="unfinished"></translation> </message> @@ -4781,22 +5139,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"/> - <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 type="unfinished"></translation> - </message> - <message> - <location line="+12"/> + <location line="+23"/> <source>%s is set very high!</source> <translation type="unfinished"></translation> </message> <message> - <location line="+20"/> - <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+41"/> + <location line="+72"/> <source>Starting network threads...</source> <translation type="unfinished"></translation> </message> @@ -4836,32 +5184,27 @@ 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="-52"/> + <location line="-59"/> <source>Insufficient funds</source> <translation>Insufficient funds</translation> </message> <message> - <location line="-102"/> - <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 type="unfinished"></translation> - </message> - <message> - <location line="+12"/> + <location line="-110"/> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+41"/> + <location line="+63"/> <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> + <location line="+17"/> <source>Cannot write to data directory '%s'; check permissions.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+39"/> + <location line="+41"/> <source>Loading block index...</source> <translation>Loading block index...</translation> </message> @@ -4871,17 +5214,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satos <translation>Loading wallet...</translation> </message> <message> - <location line="-42"/> + <location line="-45"/> <source>Cannot downgrade wallet</source> <translation>Cannot downgrade wallet</translation> </message> <message> - <location line="+51"/> + <location line="+55"/> <source>Rescanning...</source> <translation>Rescanning...</translation> </message> <message> - <location line="-41"/> + <location line="-43"/> <source>Done loading</source> <translation>Done loading</translation> </message> diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts index ab674f0c7d..3896953215 100644 --- a/src/qt/locale/bitcoin_en_GB.ts +++ b/src/qt/locale/bitcoin_en_GB.ts @@ -70,8 +70,10 @@ <translation>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</translation> </message> <message> <source>&Copy Address</source> @@ -121,7 +123,7 @@ <name>AskPassphraseDialog</name> <message> <source>Passphrase Dialog</source> - <translation>Passphrase Dialog</translation> + <translation>Passphrase Dialogue</translation> </message> <message> <source>Enter passphrase</source> @@ -189,7 +191,7 @@ </message> <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> - <translation>Remember that encrypting your wallet cannot fully protect your Bitcoins from being stolen by malware infecting your computer.</translation> + <translation>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</translation> </message> <message> <source>Wallet to be encrypted</source> @@ -255,11 +257,11 @@ <name>BitcoinGUI</name> <message> <source>Sign &message...</source> - <translation>Sign &message ...</translation> + <translation>Sign &message...</translation> </message> <message> <source>Synchronizing with network...</source> - <translation>Synchronising with network ...</translation> + <translation>Synchronising with network...</translation> </message> <message> <source>&Overview</source> @@ -303,7 +305,7 @@ </message> <message> <source>&Options...</source> - <translation>&Options ...</translation> + <translation>&Options...</translation> </message> <message> <source>Modify configuration options for %1</source> @@ -311,19 +313,19 @@ </message> <message> <source>&Encrypt Wallet...</source> - <translation>&Encrypt Wallet ...</translation> + <translation>&Encrypt Wallet...</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>&Backup Wallet ...</translation> + <translation>&Backup Wallet...</translation> </message> <message> <source>&Change Passphrase...</source> - <translation>&Change Passphrase ...</translation> + <translation>&Change Passphrase...</translation> </message> <message> <source>Open &URI...</source> - <translation>Open &URI ...</translation> + <translation>Open &URI...</translation> </message> <message> <source>Create Wallet...</source> @@ -351,11 +353,11 @@ </message> <message> <source>Syncing Headers (%1%)...</source> - <translation>Syncing Headers (%1%) ...</translation> + <translation>Syncing Headers (%1%)...</translation> </message> <message> <source>Reindexing blocks on disk...</source> - <translation>Reindexing blocks on disk ...</translation> + <translation>Reindexing blocks on disk...</translation> </message> <message> <source>Proxy is <b>enabled</b>: %1</source> @@ -375,7 +377,7 @@ </message> <message> <source>&Verify message...</source> - <translation>&Verify message ...</translation> + <translation>&Verify message...</translation> </message> <message> <source>&Send</source> @@ -443,11 +445,11 @@ </message> <message> <source>Indexing blocks on disk...</source> - <translation>Indexing blocks on disk ...</translation> + <translation>Indexing blocks on disk...</translation> </message> <message> <source>Processing blocks on disk...</source> - <translation>Processing blocks on disk ...</translation> + <translation>Processing blocks on disk...</translation> </message> <message numerus="yes"> <source>Processed %n block(s) of transaction history.</source> @@ -482,6 +484,22 @@ <translation>Up to date</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Load PSBT from file...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Load Partially Signed Bitcoin Transaction</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Load PSBT from clipboard...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Load Partially Signed Bitcoin Transaction from clipboard</translation> + </message> + <message> <source>Node window</source> <translation>Node window</translation> </message> @@ -499,7 +517,7 @@ </message> <message> <source>Open a bitcoin: URI</source> - <translation>Open a Bitcoin: URI</translation> + <translation>Open a bitcoin: URI</translation> </message> <message> <source>Open Wallet</source> @@ -511,17 +529,33 @@ </message> <message> <source>Close Wallet...</source> - <translation>Close Wallet ...</translation> + <translation>Close Wallet...</translation> </message> <message> <source>Close wallet</source> <translation>Close wallet</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Close All Wallets...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Close all wallets</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Show the %1 help message to get a list with possible Bitcoin command-line options</translation> </message> <message> + <source>&Mask values</source> + <translation>&Mask values</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Mask the values in the Overview tab</translation> + </message> + <message> <source>default wallet</source> <translation>default wallet</translation> </message> @@ -535,7 +569,7 @@ </message> <message> <source>Minimize</source> - <translation>Minimise</translation> + <translation>Minimize</translation> </message> <message> <source>Zoom</source> @@ -551,11 +585,11 @@ </message> <message> <source>Connecting to peers...</source> - <translation>Connecting to peers ...</translation> + <translation>Connecting to peers...</translation> </message> <message> <source>Catching up...</source> - <translation>Catching up ...</translation> + <translation>Catching up...</translation> </message> <message> <source>Error: %1</source> @@ -630,8 +664,12 @@ <translation>Wallet is <b>encrypted</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>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</translation> + <source>Original message:</source> + <translation>Original message:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>A fatal error occurred. %1 can no longer continue safely and will quit.</translation> </message> </context> <context> @@ -835,6 +873,14 @@ <translation>Make Blank Wallet</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Use descriptors for scriptPubKey management</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Descriptor Wallet</translation> + </message> + <message> <source>Create</source> <translation>Create</translation> </message> @@ -952,7 +998,7 @@ </message> <message> <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation>Reverting this setting requires re-downloading the entire Blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</translation> + <translation>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</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> @@ -960,7 +1006,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 afterwards 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 afterward to keep your disk usage low.</translation> </message> <message> <source>Use the default data directory</source> @@ -1023,11 +1069,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>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 synchronising with the Bitcoin network, as detailed below.</translation> + <translation>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.</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>Attempting to spend Bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</translation> + <translation>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</translation> </message> <message> <source>Number of blocks left</source> @@ -1035,7 +1081,7 @@ </message> <message> <source>Unknown...</source> - <translation>Unknown ...</translation> + <translation>Unknown...</translation> </message> <message> <source>Last block time</source> @@ -1051,7 +1097,7 @@ </message> <message> <source>calculating...</source> - <translation>calculating ...</translation> + <translation>calculating...</translation> </message> <message> <source>Estimated time left until synced</source> @@ -1071,14 +1117,14 @@ </message> <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> - <translation>Unknown. Syncing Headers (%1, %2%) ...</translation> + <translation>Unknown. Syncing Headers (%1, %2%)...</translation> </message> </context> <context> <name>OpenURIDialog</name> <message> <source>Open bitcoin URI</source> - <translation>Open Bitcoin URI</translation> + <translation>Open bitcoin URI</translation> </message> <message> <source>URI:</source> @@ -1101,7 +1147,7 @@ </message> <message> <source>Opening Wallet <b>%1</b>...</source> - <translation>Opening Wallet <b>%1</b> ...</translation> + <translation>Opening Wallet <b>%1</b>...</translation> </message> </context> <context> @@ -1139,10 +1185,6 @@ <translation>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Hide the icon from the system tray.</translation> </message> @@ -1152,7 +1194,7 @@ </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>Minimise 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.</translation> + <translation>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.</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> @@ -1275,24 +1317,20 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</translation> - </message> - <message> <source>&Window</source> <translation>&Window</translation> </message> <message> <source>Show only a tray icon after minimizing the window.</source> - <translation>Show on a tray icon after minimising the window.</translation> + <translation>Show only a tray icon after minimizing the window.</translation> </message> <message> <source>&Minimize to the tray instead of the taskbar</source> - <translation>&Minimise to the tray instead of the task bar</translation> + <translation>&Minimize to the tray instead of the taskbar</translation> </message> <message> <source>M&inimize on close</source> - <translation>M&inimise on close</translation> + <translation>M&inimize on close</translation> </message> <message> <source>&Display</source> @@ -1319,6 +1357,14 @@ <translation>Whether to show coin control features or not.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&Third party transaction URLs</translation> </message> @@ -1387,7 +1433,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>The displayed information may be out of date. Your Wallet automatically synchronises with the Bitcoin Network after a connection is established, but this process has not been completed yet.</translation> + <translation>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.</translation> </message> <message> <source>Watch-only:</source> @@ -1453,6 +1499,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Current total balance in watch-only addresses</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Sign Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Broadcast Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Copy to Clipboard</translation> + </message> + <message> + <source>Save...</source> + <translation>Save...</translation> + </message> + <message> + <source>Close</source> + <translation>Close</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Failed to load transaction: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Failed to sign transaction: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Could not sign any more inputs.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Signed %1 inputs, but more signatures are still required.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Signed transaction successfully. Transaction is ready to broadcast.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Unknown error processing transaction.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Transaction broadcast successfully! Transaction ID: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Transaction broadcast failed: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT copied to clipboard.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Save Transaction Data</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Partially Signed Transaction (Binary) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT saved to disk.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation> * Sends %1 to %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Unable to calculate transaction fee or total transaction amount.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Pays transaction fee: </translation> + </message> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Transaction has %1 unsigned inputs.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Transaction is missing some information about inputs.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Transaction still needs signature(s).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(But this wallet cannot sign transactions.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(But this wallet does not have the right keys.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Transaction is fully signed and ready for broadcast.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Transaction status is unknown.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1462,7 +1635,7 @@ </message> <message> <source>Cannot start bitcoin: click-to-pay handler</source> - <translation>Cannot start Bitcoin: click-to-pay handler</translation> + <translation>Cannot start bitcoin: click-to-pay handler</translation> </message> <message> <source>URI handling</source> @@ -1619,8 +1792,12 @@ <translation>Error: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Error initializing settings: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> - <translation>%1 didn't exit safely yet ...</translation> + <translation>%1 didn't yet exit safely...</translation> </message> <message> <source>unknown</source> @@ -1631,7 +1808,7 @@ <name>QRImageWidget</name> <message> <source>&Save Image...</source> - <translation>&Save Image ...</translation> + <translation>&Save Image...</translation> </message> <message> <source>&Copy Image</source> @@ -1698,7 +1875,7 @@ </message> <message> <source>Startup time</source> - <translation>Start up time</translation> + <translation>Startup time</translation> </message> <message> <source>Network</source> @@ -1717,10 +1894,6 @@ <translation>Block chain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Current number of blocks</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memory Pool</translation> </message> @@ -1734,7 +1907,7 @@ </message> <message> <source>Wallet: </source> - <translation>Wallet:</translation> + <translation>Wallet: </translation> </message> <message> <source>(none)</source> @@ -1765,10 +1938,6 @@ <translation>Select a peer to view detailed information.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Whitelisted</translation> - </message> - <message> <source>Direction</source> <translation>Direction</translation> </message> @@ -1789,6 +1958,14 @@ <translation>Synced Blocks</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>The mapped Autonomous System used for diversifying peer selection.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapped AS</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> @@ -1797,6 +1974,10 @@ <translation>Node window</translation> </message> <message> + <source>Current block height</source> + <translation>Current block height</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>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</translation> </message> @@ -1809,12 +1990,12 @@ <translation>Increase font size</translation> </message> <message> - <source>Services</source> - <translation>Services</translation> + <source>Permissions</source> + <translation>Permissions</translation> </message> <message> - <source>Ban Score</source> - <translation>Ban Score</translation> + <source>Services</source> + <translation>Services</translation> </message> <message> <source>Connection Time</source> @@ -1930,7 +2111,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>WARNING: Scammers have been active, telling users to type commands here and stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.</translation> + <translation>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.</translation> </message> <message> <source>Network activity disabled</source> @@ -1965,14 +2146,6 @@ <translation>Outbound</translation> </message> <message> - <source>Yes</source> - <translation>Yes</translation> - </message> - <message> - <source>No</source> - <translation>No</translation> - </message> - <message> <source>Unknown</source> <translation>Unknown</translation> </message> @@ -2071,56 +2244,60 @@ <source>Copy amount</source> <translation>Copy amount</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Could not unlock wallet.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Could not generate new %1 address</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Code</translation> + <source>Request payment to ...</source> + <translation>Request payment to ...</translation> </message> <message> - <source>Copy &URI</source> - <translation>Copy &URI</translation> + <source>Address:</source> + <translation>Address:</translation> </message> <message> - <source>Copy &Address</source> - <translation>Copy &Address</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>&Save Image ...</translation> + <source>Amount:</source> + <translation>Amount:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Request payment to %1</translation> + <source>Label:</source> + <translation>Label:</translation> </message> <message> - <source>Payment information</source> - <translation>Payment information</translation> + <source>Message:</source> + <translation>Message:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Wallet:</translation> </message> <message> - <source>Address</source> - <translation>Address</translation> + <source>Copy &URI</source> + <translation>Copy &URI</translation> </message> <message> - <source>Amount</source> - <translation>Amount</translation> + <source>Copy &Address</source> + <translation>Copy &Address</translation> </message> <message> - <source>Label</source> - <translation>Label</translation> + <source>&Save Image...</source> + <translation>&Save Image...</translation> </message> <message> - <source>Message</source> - <translation>Message</translation> + <source>Request payment to %1</source> + <translation>Request payment to %1</translation> </message> <message> - <source>Wallet</source> - <translation>Wallet</translation> + <source>Payment information</source> + <translation>Payment information</translation> </message> </context> <context> @@ -2166,7 +2343,7 @@ </message> <message> <source>Inputs...</source> - <translation>Inputs ...</translation> + <translation>Inputs...</translation> </message> <message> <source>automatically selected</source> @@ -2214,11 +2391,11 @@ </message> <message> <source>Choose...</source> - <translation>Choose ...</translation> + <translation>Choose...</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>Using the fallback fee 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.</translation> + <translation>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.</translation> </message> <message> <source>Warning: Fee estimation is currently not possible.</source> @@ -2250,7 +2427,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> - <translation>(Smart fee not initialised yet. This usually takes a few blocks ...)</translation> + <translation>(Smart fee not initialized yet. This usually takes a few blocks...)</translation> </message> <message> <source>Send to multiple recipients at once</source> @@ -2278,7 +2455,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation>A too low fee might result in a never-confirming transaction (read the tooltip)</translation> + <translation>A too low fee might result in a never confirming transaction (read the tooltip)</translation> </message> <message> <source>Confirmation time target:</source> @@ -2369,8 +2546,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Are you sure you want to send?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + <source>Create Unsigned</source> + <translation>Create Unsigned</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Save Transaction Data</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Partially Signed Transaction (Binary) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT saved</translation> </message> <message> <source>or</source> @@ -2381,6 +2570,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Please, review your transaction.</translation> </message> @@ -2409,18 +2602,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Confirm transaction proposal</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Copy PSBT to clipboard</translation> - </message> - <message> <source>Send</source> <translation>Send</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT copied</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Watch-only balance:</translation> </message> @@ -2568,7 +2753,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <name>ShutdownWindow</name> <message> <source>%1 is shutting down...</source> - <translation>%1 is shutting down ...</translation> + <translation>%1 is shutting down...</translation> </message> <message> <source>Do not shut down the computer until this window disappears.</source> @@ -3050,7 +3235,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Range...</source> - <translation>Range ...</translation> + <translation>Range...</translation> </message> <message> <source>Received with</source> @@ -3074,7 +3259,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Enter address, transaction id, or label to search</source> - <translation>Enter address, transaction id or label to search.</translation> + <translation>Enter address, transaction id, or label to search</translation> </message> <message> <source>Min amount</source> @@ -3202,12 +3387,28 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Close all wallets</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Are you sure you wish to close all wallets?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>No wallet has been loaded.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Create a new wallet</translation> </message> </context> <context> @@ -3222,7 +3423,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Increasing transaction fee failed</source> - <translation>Increasing transaction fee failed.</translation> + <translation>Increasing transaction fee failed</translation> </message> <message> <source>Do you want to increase the fee?</source> @@ -3262,7 +3463,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>Could not commit transaction.</translation> + <translation>Could not commit transaction</translation> </message> <message> <source>default wallet</source> @@ -3280,6 +3481,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Export the data in the current tab to a file</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Unable to decode PSBT from clipboard (invalid base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Load Transaction Data</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Partially Signed Transaction (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PSBT file must be smaller than 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Unable to decode PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Backup Wallet</translation> </message> @@ -3312,7 +3537,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <name>bitcoin-core</name> <message> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> - <translation>Distributed under the MIT software license, see the accompanying file %s or %s.</translation> + <translation>Distributed under the MIT software license, see the accompanying file %s or %s</translation> </message> <message> <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> @@ -3323,12 +3548,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Error: A fatal internal error occurred, see debug.log for details</translation> - </message> - <message> <source>Pruning blockstore...</source> - <translation>Pruning blockstore ...</translation> + <translation>Pruning blockstore...</translation> </message> <message> <source>Unable to start HTTP server. See debug log for details.</source> @@ -3339,10 +3560,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>The %s developers</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Cannot obtain a lock on data directory %s. %s is probably already running.</translation> </message> @@ -3372,7 +3589,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> - <translation>This is the transaction fee you may discard if change is smaller than dust at this level.</translation> + <translation>This is the transaction fee you may discard if change is smaller than dust at this level</translation> </message> <message> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> @@ -3380,7 +3597,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</source> - <translation>Unable to rewind the database to a pre-fork state. You will need to re-download the blockchain</translation> + <translation>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</translation> </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> @@ -3391,14 +3608,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d of last 100 blocks have unexpected version.</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrupt, salvage failed</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool must be at least %d MB</translation> </message> @@ -3436,11 +3645,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Error initializing block database</source> - <translation>Error initialising block database</translation> + <translation>Error initializing block database</translation> </message> <message> <source>Error initializing wallet database environment %s!</source> - <translation>Error initialising wallet database environment %s!</translation> + <translation>Error initializing wallet database environment %s!</translation> </message> <message> <source>Error loading %s</source> @@ -3472,11 +3681,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Failed to rescan the wallet during initialization</source> - <translation>Failed to rescan the wallet during initialisation.</translation> + <translation>Failed to rescan the wallet during initialization</translation> </message> <message> <source>Importing...</source> - <translation>Importing ...</translation> + <translation>Importing...</translation> </message> <message> <source>Incorrect or no genesis block found. Wrong datadir for network?</source> @@ -3484,7 +3693,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Initialization sanity check failed. %s is shutting down.</source> - <translation>Initialisation sanity check failed. %s is shutting down.</translation> + <translation>Initialization sanity check failed. %s is shutting down.</translation> </message> <message> <source>Invalid P2P permission: '%s'</source> @@ -3520,15 +3729,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Loading P2P addresses...</source> - <translation>Loading P2P addresses ...</translation> - </message> - <message> - <source>Error: Disk space is too low!</source> - <translation>Error: Disk space is too low!</translation> + <translation>Loading P2P addresses...</translation> </message> <message> <source>Loading banlist...</source> - <translation>Loading banlist ...</translation> + <translation>Loading banlist...</translation> </message> <message> <source>Not enough file descriptors available.</source> @@ -3544,11 +3749,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Replaying blocks...</source> - <translation>Replaying blocks ...</translation> + <translation>Replaying blocks...</translation> </message> <message> <source>Rewinding blocks...</source> - <translation>Rewinding blocks ...</translation> + <translation>Rewinding blocks...</translation> </message> <message> <source>The source code is available from %s.</source> @@ -3556,7 +3761,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Transaction fee and change calculation failed</source> - <translation>Transaction fee and change calculation failed.</translation> + <translation>Transaction fee and change calculation failed</translation> </message> <message> <source>Unable to bind to %s on this computer. %s is probably already running.</source> @@ -3580,7 +3785,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Verifying blocks...</source> - <translation>Verifying blocks ...</translation> + <translation>Verifying blocks...</translation> </message> <message> <source>Wallet needed to be rewritten: restart %s to complete</source> @@ -3591,6 +3796,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Error: Listening for incoming connections failed (listen returned error %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</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>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</translation> </message> @@ -3599,22 +3812,54 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>The transaction amount is too small to send after the fee has been deducted</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</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>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>A fatal internal error occurred, see debug.log for details</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Cannot set -peerblockfilters without -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Disk space is too low!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Error reading from database, shutting down.</translation> </message> <message> <source>Error upgrading chainstate database</source> - <translation>Error upgrading chainstate database.</translation> + <translation>Error upgrading chainstate database</translation> </message> <message> <source>Error: Disk space is low for %s</source> <translation>Error: Disk space is low for %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Error: Keypool ran out, please call keypoolrefill first</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Fee rate (%s) is lower than the minimum fee rate setting (%s)</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Invalid -onion address or hostname: '%s'</translation> </message> @@ -3635,6 +3880,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Need to specify a port with -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Prune mode is incompatible with -blockfilterindex.</translation> </message> @@ -3652,15 +3901,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Specified -walletdir "%s" does not exist</source> - <translation>Specified -walletdir "%s" does not exist.</translation> + <translation>Specified -walletdir "%s" does not exist</translation> </message> <message> <source>Specified -walletdir "%s" is a relative path</source> - <translation>Specified -walletdir "%s" is a relative path.</translation> + <translation>Specified -walletdir "%s" is a relative path</translation> </message> <message> <source>Specified -walletdir "%s" is not a directory</source> - <translation>Specified -walletdir "%s" is not a directory.</translation> + <translation>Specified -walletdir "%s" is not a directory</translation> </message> <message> <source>The specified config file %s does not exist @@ -3694,7 +3943,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Unable to generate initial keys</source> - <translation>Unable to generate initial keys.</translation> + <translation>Unable to generate initial keys</translation> </message> <message> <source>Unknown -blockfilterindex value %s.</source> @@ -3702,17 +3951,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Verifying wallet(s)...</source> - <translation>Verifying wallet(s) ...</translation> + <translation>Verifying wallet(s)...</translation> </message> <message> <source>Warning: unknown new rules activated (versionbit %i)</source> <translation>Warning: unknown new rules activated (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Zapping all transactions from wallet ...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation> </message> @@ -3725,10 +3970,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</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>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.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s is set very high!</translation> </message> @@ -3738,7 +3979,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Starting network threads...</source> - <translation>Starting network threads ...</translation> + <translation>Starting network threads...</translation> </message> <message> <source>The wallet will avoid paying less than the minimum relay fee.</source> @@ -3754,15 +3995,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Transaction amounts must not be negative</source> - <translation>Transaction amounts must not be negative.</translation> + <translation>Transaction amounts must not be negative</translation> </message> <message> <source>Transaction has too long of a mempool chain</source> - <translation>Transaction has too long of a mempool chain.</translation> + <translation>Transaction has too long of a mempool chain</translation> </message> <message> <source>Transaction must have at least one recipient</source> - <translation>Transaction must have at least one recipient.</translation> + <translation>Transaction must have at least one recipient</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> @@ -3773,10 +4014,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Insufficient funds</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> @@ -3790,11 +4027,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Loading block index...</source> - <translation>Loading block index ...</translation> + <translation>Loading block index...</translation> </message> <message> <source>Loading wallet...</source> - <translation>Loading wallet ...</translation> + <translation>Loading wallet...</translation> </message> <message> <source>Cannot downgrade wallet</source> @@ -3802,7 +4039,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Rescanning...</source> - <translation>Rescanning ...</translation> + <translation>Rescanning...</translation> </message> <message> <source>Done loading</source> diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts index f4ce75f428..ab0167cf17 100644 --- a/src/qt/locale/bitcoin_eo.ts +++ b/src/qt/locale/bitcoin_eo.ts @@ -439,11 +439,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Monujo estas <b>ĉifrita</b> kaj aktuale <b>ŝlosita</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Okazis neriparebla eraro. Bitmono ne plu povas sekure daŭri, do ĝi sekure ĉesos.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -893,6 +889,13 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>aŭ</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1043,10 +1046,6 @@ <translation>Blokĉeno</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Aktuala nombro de blokoj</translation> - </message> - <message> <source>Received</source> <translation>Ricevita</translation> </message> @@ -1153,12 +1152,24 @@ <source>Copy amount</source> <translation>Kopii sumon</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Ne eblis malŝlosi monujon.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-kodo</translation> + <source>Amount:</source> + <translation>Sumo:</translation> + </message> + <message> + <source>Label:</source> + <translation>Etikedo:</translation> + </message> + <message> + <source>Message:</source> + <translation>Mesaĝo:</translation> </message> <message> <source>Copy &URI</source> @@ -1180,30 +1191,6 @@ <source>Payment information</source> <translation>Paginformoj</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adreso</translation> - </message> - <message> - <source>Amount</source> - <translation>Sumo</translation> - </message> - <message> - <source>Label</source> - <translation>Etikedo</translation> - </message> - <message> - <source>Message</source> - <translation>Mesaĝo</translation> - </message> - <message> - <source>Wallet</source> - <translation>Monujo</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -1910,6 +1897,10 @@ <translation>Eksporti la datumojn el la aktuala langeto al dosiero</translation> </message> <message> + <source>Error</source> + <translation>Eraro</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Krei sekurkopion de monujo</translation> </message> diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index b681cff011..0b32703779 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -3,11 +3,11 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Haga clic con el botón derecho para editar una dirección o etiqueta</translation> + <translation>Haz click con el botón derecho para editar una dirección o etiqueta</translation> </message> <message> <source>Create a new address</source> - <translation>Crear una nueva dirección</translation> + <translation>Crear una dirección nueva</translation> </message> <message> <source>&New</source> @@ -31,7 +31,7 @@ </message> <message> <source>Enter address or label to search</source> - <translation>Introduzca la dirección, ID de transacción o etiqueta a buscar.</translation> + <translation>Introduce la dirección o etiqueta que quieres buscar</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -43,11 +43,11 @@ </message> <message> <source>&Delete</source> - <translation>Eliminar</translation> + <translation>&Borrar</translation> </message> <message> <source>Choose the address to send coins to</source> - <translation>Escoja la dirección a la que se enviarán monedas</translation> + <translation>Elige la dirección a la que se enviarán las monedas</translation> </message> <message> <source>Choose the address to receive coins with</source> @@ -70,12 +70,14 @@ <translation>Estas son sus direcciones Bitcoin para enviar pagos. Compruebe siempre la cantidad y la dirección de recibo antes de transferir monedas.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Estas son sus direcciones Bitcoin para la recepción de pagos. Use el botón 'Crear una nueva dirección para recepción' en la pestaña Recibir para crear nuevas direcciones</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Estas son sus direcciones Bitcoin para la recepción de pagos. Use el botón 'Crear una nueva dirección para recepción' en la pestaña Recibir para crear nuevas direcciones. +Firmar solo es posible con correos del tipo Legacy.</translation> </message> <message> <source>&Copy Address</source> - <translation>Copiar dirección</translation> + <translation>&Copiar dirección</translation> </message> <message> <source>Copy &Label</source> @@ -95,7 +97,7 @@ </message> <message> <source>Exporting Failed</source> - <translation>La exportación falló</translation> + <translation>La exportación ha fallado</translation> </message> <message> <source>There was an error trying to save the address list to %1. Please try again.</source> @@ -125,7 +127,7 @@ </message> <message> <source>Enter passphrase</source> - <translation>Introducir contraseña</translation> + <translation>Introduce la contraseña</translation> </message> <message> <source>New passphrase</source> @@ -141,23 +143,23 @@ </message> <message> <source>Encrypt wallet</source> - <translation>Cifrar monedero</translation> + <translation>Cifrar cartera</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation>Esta operación requiere su contraseña para desbloquear el monedero.</translation> + <translation>Esta operación necesita la contraseña para desbloquear la cartera</translation> </message> <message> <source>Unlock wallet</source> - <translation>Desbloquear monedero</translation> + <translation>Desbloquear cartera</translation> </message> <message> <source>This operation needs your wallet passphrase to decrypt the wallet.</source> - <translation>Esta operación requiere su contraseña para descifrar el monedero.</translation> + <translation>Esta operación necesita la contraseña para desbloquear la cartera.</translation> </message> <message> <source>Decrypt wallet</source> - <translation>Descifrar monedero</translation> + <translation>Descifrar cartera</translation> </message> <message> <source>Change passphrase</source> @@ -165,7 +167,7 @@ </message> <message> <source>Confirm wallet encryption</source> - <translation>Confirmar el cifrado del monedero</translation> + <translation>Confirma el cifrado de esta cartera</translation> </message> <message> <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> @@ -173,47 +175,47 @@ </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> - <translation>¿Seguro que desea cifrar su monedero?</translation> + <translation>¿Seguro que quieres cifrar tu cartera?</translation> </message> <message> <source>Wallet encrypted</source> - <translation>Monedero cifrado</translation> + <translation>Cartera encriptada</translation> </message> <message> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation>Introduzca la nueva contraseña del monedero. <br/>Por favor utilice una contraseña de <b>diez o más caracteres aleatorios</b>, u <b>ocho o más palabras</b>.</translation> + <translation>Introduce la contraseña nueva para la cartera. <br/>Por favor utiliza una contraseña de <b>diez o más caracteres aleatorios</b>, u <b>ocho o más palabras</b>.</translation> </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation>Introduzca la contraseña antigua y la nueva para el monedero.</translation> + <translation>Introduce la contraseña antigua y la nueva para la cartera.</translation> </message> <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> - <translation>Recuerde que cifrar su monedero no garantiza mantener a salvo sus bitcoins en caso de tener virus en el computador.</translation> + <translation>Recuerda que cifrar tu cartera no garantiza la protección de tus bitcoin si tu ordenador es infectado con malware.</translation> </message> <message> <source>Wallet to be encrypted</source> - <translation>Monedero para cifrar</translation> + <translation>Cartera a cifrar</translation> </message> <message> <source>Your wallet is about to be encrypted. </source> - <translation>Su monedero va a ser cifrado</translation> + <translation>Tu cartera va a ser cifrada</translation> </message> <message> <source>Your wallet is now encrypted. </source> - <translation>Su monedero está ahora cifrado</translation> + <translation>Tu cartera ya está cifrada</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>IMPORTANTE: Cualquier copia de seguridad anterior que haya hecho de su archivo del monedero debe ser reemplazada por el archivo del monedero cifrado y recién generado. Por razones de seguridad, las copias de seguridad anteriores del archivo del monedero sin cifrar serán inútiles tan pronto como empiece a usar el nuevo monedero cifrado.</translation> + <translation>IMPORTANTE: Cualquier copia de seguridad que hayas hecho del archivo de tu cartera debe ser reemplazada por el archivo cifrado de la cartera recién generado. Por razones de seguridad, las copias de seguridad anteriores del archivo de la cartera sin cifrar serán inútiles cuando empiece a usar la nueva cartera cifrada.</translation> </message> <message> <source>Wallet encryption failed</source> - <translation>Cifrado del monedero fallido</translation> + <translation>El cifrado de la cartera ha fallado</translation> </message> <message> <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> - <translation>El cifrado del monedero falló debido a un error interno. Su monedero no fue cifrado.</translation> + <translation>El cifrado de la cartera ha fallado debido a un error interno. Tu cartera no ha sido cifrada.</translation> </message> <message> <source>The supplied passphrases do not match.</source> @@ -221,19 +223,19 @@ </message> <message> <source>Wallet unlock failed</source> - <translation>Desbloquear el monedero falló.</translation> + <translation>El desbloqueo de la cartera ha fallado</translation> </message> <message> <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation>La contraseña ingresada para el descifrado del monedero es incorrecta.</translation> + <translation>La contraseña introducida descifrar la cartera es incorrecta.</translation> </message> <message> <source>Wallet decryption failed</source> - <translation>El descifrado del monedero falló</translation> + <translation>El descifrado de la cartera ha fallado</translation> </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation>La contraseña del monedero ha sido cambiada con éxito.</translation> + <translation>La contraseña de la cartera ha sido cambiada.</translation> </message> <message> <source>Warning: The Caps Lock key is on!</source> @@ -248,7 +250,7 @@ </message> <message> <source>Banned Until</source> - <translation>Prohibido Hasta</translation> + <translation>Prohibido hasta</translation> </message> </context> <context> @@ -267,7 +269,7 @@ </message> <message> <source>Show general overview of wallet</source> - <translation>Mostrar vista general del monedero</translation> + <translation>Mostrar vista general de la cartera</translation> </message> <message> <source>&Transactions</source> @@ -311,11 +313,11 @@ </message> <message> <source>&Encrypt Wallet...</source> - <translation>&Cifrar monedero…</translation> + <translation>&Cifrar cartera…</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>&Copia de respaldo del monedero...</translation> + <translation>&Copia de seguridad de la cartera...</translation> </message> <message> <source>&Change Passphrase...</source> @@ -327,15 +329,15 @@ </message> <message> <source>Create Wallet...</source> - <translation>Crear monedero...</translation> + <translation>Crear cartera...</translation> </message> <message> <source>Create a new wallet</source> - <translation>Crear monedero nuevo</translation> + <translation>Crear nueva cartera</translation> </message> <message> <source>Wallet:</source> - <translation>Monedero:</translation> + <translation>Cartera:</translation> </message> <message> <source>Click to disable network activity.</source> @@ -395,7 +397,7 @@ </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation>Cifrar las claves privadas de su monedero</translation> + <translation>Cifrar las claves privadas que pertenecen a tu cartera</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> @@ -471,7 +473,7 @@ </message> <message> <source>Warning</source> - <translation>Aviso</translation> + <translation>Advertencia</translation> </message> <message> <source>Information</source> @@ -482,6 +484,22 @@ <translation>Actualizado</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Cargar PSBT desde el archivo...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Cargar una transacción de Bitcoin parcialmente firmada</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Cargar PSBT desde el portapapeles...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Cargar una transacción de Bitcoin parcialmente firmada desde el Portapapeles</translation> + </message> + <message> <source>Node window</source> <translation>Ventana de nodo</translation> </message> @@ -503,31 +521,47 @@ </message> <message> <source>Open Wallet</source> - <translation>Abrir Monedero</translation> + <translation>Abrir cartera</translation> </message> <message> <source>Open a wallet</source> - <translation>Abrir un monedero</translation> + <translation>Abrir una cartera</translation> </message> <message> <source>Close Wallet...</source> - <translation>Cerrar Monedero...</translation> + <translation>Cerrar cartera...</translation> </message> <message> <source>Close wallet</source> - <translation>Cerrar monedero</translation> + <translation>Cerrar cartera</translation> + </message> + <message> + <source>Close All Wallets...</source> + <translation>Cerrar todas las carteras...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Cerrar todas las carteras</translation> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation>Muestre el mensaje de ayuda %1 para obtener una lista con posibles opciones de línea de comandos de Bitcoin</translation> + <translation>Muestra el mensaje de ayuda %1 para obtener una lista con posibles opciones de línea de comandos de Bitcoin.</translation> + </message> + <message> + <source>&Mask values</source> + <translation>&Esconder valores</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Esconder los valores de la ventana de previsualización</translation> </message> <message> <source>default wallet</source> - <translation>Monedero predeterminado</translation> + <translation>Cartera predeterminada</translation> </message> <message> <source>No wallets available</source> - <translation>No hay monederos disponibles.</translation> + <translation>No hay carteras disponibles</translation> </message> <message> <source>&Window</source> @@ -580,7 +614,7 @@ <message> <source>Wallet: %1 </source> - <translation>Monedero: %1 + <translation>Cartera: %1 </translation> </message> <message> @@ -627,11 +661,15 @@ </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation>El monedero está <b>cifrado</b> y actualmente <b>bloqueado</b></translation> + <translation>La cartera está <b>cifrada</b> y <b>bloqueada</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Se produjo un error fatal. Bitcoin ya no puede continuar de manera segura y se cerrará</translation> + <source>Original message:</source> + <translation>Mensaje original:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Ha ocurrido un error fatal. %1 no puede seguir seguro y se cerrará.</translation> </message> </context> <context> @@ -793,7 +831,7 @@ </message> <message> <source>Create wallet failed</source> - <translation>Crear monedero falló</translation> + <translation>Error al crear cartera</translation> </message> <message> <source>Create wallet warning</source> @@ -812,7 +850,7 @@ </message> <message> <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation>Encriptar monedero. El monedero será cifrado con la contraseña que elija.</translation> + <translation>Cifrar monedero. El monedero será cifrado con la contraseña que elija.</translation> </message> <message> <source>Encrypt Wallet</source> @@ -835,6 +873,14 @@ <translation>Crear monedero vacío</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Use descriptores para la gestión de scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Descriptor del monedero</translation> + </message> + <message> <source>Create</source> <translation>Crear</translation> </message> @@ -992,7 +1038,7 @@ </message> <message> <source>The wallet will also be stored in this directory.</source> - <translation>El monedero también se almacenará en este directorio.</translation> + <translation>La cartera también se almacenará en este directorio.</translation> </message> <message> <source>Error: Specified data directory "%1" cannot be created.</source> @@ -1039,11 +1085,11 @@ </message> <message> <source>Last block time</source> - <translation>Hora del último bloque.</translation> + <translation>Hora del último bloque</translation> </message> <message> <source>Progress</source> - <translation>Progreso.</translation> + <translation>Progreso</translation> </message> <message> <source>Progress increase per hour</source> @@ -1093,7 +1139,7 @@ </message> <message> <source>Open wallet warning</source> - <translation>Advertencia sobre apertura de monedero</translation> + <translation>Ver aviso sobre la cartera</translation> </message> <message> <source>default wallet</source> @@ -1115,6 +1161,10 @@ <translation>&Principal</translation> </message> <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Iniciar automaticamente %1 al encender el sistema.</translation> + </message> + <message> <source>&Start %1 on system login</source> <translation>& Comience %1 en el inicio de sesión del sistema</translation> </message> @@ -1135,16 +1185,12 @@ <translation>Muestra si el proxy SOCKS5 suministrado se utiliza para llegar a los pares a través de este tipo de red.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Use SOCKS&5 y proxy por separado para llegar a sus compañeros a través de los servicios ocultos de Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Ocultar el icono de la bandeja del sistema.</translation> </message> <message> <source>&Hide tray icon</source> - <translation>Ocultar icono de bandeja</translation> + <translation>&Ocultar el icono de la bandeja</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> @@ -1164,7 +1210,7 @@ </message> <message> <source>Reset all client options to default.</source> - <translation>Restablecer todas las opciones del cliente a las predeterminadas.</translation> + <translation>Restablecer todas las opciones predeterminadas del cliente.</translation> </message> <message> <source>&Reset Options</source> @@ -1200,7 +1246,7 @@ </message> <message> <source>W&allet</source> - <translation>Monedero</translation> + <translation>C&artera</translation> </message> <message> <source>Expert</source> @@ -1220,7 +1266,7 @@ </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>Abrir automáticamente el puerto del cliente Bitcoin en el router. Esta opción solo funciona si el router admite UPnP y está activado.</translation> + <translation>Abrir automáticamente el puerto del cliente Bitcoin en el router. Esta opción solo funciona cuando el router admite UPnP y está activado.</translation> </message> <message> <source>Map port using &UPnP</source> @@ -1236,7 +1282,7 @@ </message> <message> <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> - <translation>Conéctese a la red de Bitcoin a través de un proxy SOCKS5.</translation> + <translation>Conectar a la red de Bitcoin a través de un proxy SOCKS5.</translation> </message> <message> <source>&Connect through SOCKS5 proxy (default proxy):</source> @@ -1271,16 +1317,12 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Conéctese a la red de Bitcoin a través de un proxy SOCKS5 separado para los servicios Tor ocultos.</translation> - </message> - <message> <source>&Window</source> <translation>&Ventana</translation> </message> <message> <source>Show only a tray icon after minimizing the window.</source> - <translation>Minimizar la ventana a la bandeja de iconos del sistema.</translation> + <translation>Mostrar solo un icono de sistema después de minimizar la ventana</translation> </message> <message> <source>&Minimize to the tray instead of the taskbar</source> @@ -1315,6 +1357,14 @@ <translation>Mostrar o no características de control de moneda</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Conéctese a la red de Bitcoin a través de un proxy SOCKS5 separado para los servicios Tor ocultos.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Usar proxy SOCKS&5 para alcanzar nodos via servicios ocultos Tor:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>URLs de transacciones de terceros</translation> </message> @@ -1324,7 +1374,7 @@ </message> <message> <source>&OK</source> - <translation>&Aceptar</translation> + <translation>&OK</translation> </message> <message> <source>&Cancel</source> @@ -1379,7 +1429,7 @@ <name>OverviewPage</name> <message> <source>Form</source> - <translation>Desde</translation> + <translation>Formulario</translation> </message> <message> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> @@ -1395,7 +1445,7 @@ </message> <message> <source>Your current spendable balance</source> - <translation>Su balance actual gastable</translation> + <translation>Su saldo actual gastable</translation> </message> <message> <source>Pending:</source> @@ -1403,7 +1453,7 @@ </message> <message> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> - <translation>Total de transacciones que deben ser confirmadas y que no cuentan aun con el balance gastable necesario.</translation> + <translation>Total de transacciones que deben ser confirmadas y que no cuentan con el saldo disponible necesario.</translation> </message> <message> <source>Immature:</source> @@ -1449,6 +1499,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Saldo total actual en direcciones de solo-ver</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Modo de privacidad activado para la pestaña de visión general. Para desenmascarar los valores, desmarcar los valores de Configuración->Máscara.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialogo</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Firmar Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Emitir Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Copiar al portapapeles</translation> + </message> + <message> + <source>Save...</source> + <translation>Guardar...</translation> + </message> + <message> + <source>Close</source> + <translation>Cerrar</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Error en la carga de la transacción: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Error en la firma de la transacción: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>No se han podido firmar más entradas.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Se han firmado %1 entradas, pero aún se requieren más firmas.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Se ha firmado correctamente. La transacción está lista para difundirse.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Error desconocido al procesar la transacción.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>¡La transacción se ha difundido correctamente! Código ID de la transacción: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Ha habido un error en la difusión de la transacción: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT copiado al portapapeles</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Guardar datos de la transacción</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transacción firmada de manera parcial (Binaria) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT guardado en la memoria.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>* Envia %1 a %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>No se ha podido calcular la comisión por transacción o la totalidad de la cantidad de la transacción.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Pagar comisión de transacción:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Monto total</translation> + </message> + <message> + <source>or</source> + <translation>o</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>La transacción tiene %1 entradas no firmadas.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Le falta alguna información sobre entradas a la transacción.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>La transacción aún necesita firma(s).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Este monedero no puede firmar transacciones.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Este monedero no tiene las claves adecuadas.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>La transacción se ha firmado correctamente y está lista para difundirse.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>El estatus de la transacción es desconocido.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1713,10 +1890,6 @@ <translation>Cadena de bloques</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Número actual de bloques</translation> - </message> - <message> <source>Memory Pool</source> <translation>Grupo de memoria</translation> </message> @@ -1761,10 +1934,6 @@ <translation>Seleccione un par para ver información detallada.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Incluido en la lista blanca</translation> - </message> - <message> <source>Direction</source> <translation>Dirección</translation> </message> @@ -1785,6 +1954,14 @@ <translation>Bloques sincronizados</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>El Sistema Autónomo mapeado utilizado para la selección diversificada de participantes.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>SA Mapeado</translation> + </message> + <message> <source>User Agent</source> <translation>Agente de usuario</translation> </message> @@ -1793,6 +1970,10 @@ <translation>Ventana de nodo</translation> </message> <message> + <source>Current block height</source> + <translation>Altura del bloque actual</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>Abrir el archivo de depuración %1 desde el directorio de datos actual. Puede tardar unos segundos para ficheros de gran tamaño.</translation> </message> @@ -1805,12 +1986,12 @@ <translation>Aumentar el tamaño de la fuente</translation> </message> <message> - <source>Services</source> - <translation>Servicios</translation> + <source>Permissions</source> + <translation>Permisos</translation> </message> <message> - <source>Ban Score</source> - <translation>Puntuación Ban</translation> + <source>Services</source> + <translation>Servicios</translation> </message> <message> <source>Connection Time</source> @@ -1961,14 +2142,6 @@ <translation>Salida</translation> </message> <message> - <source>Yes</source> - <translation>Sí</translation> - </message> - <message> - <source>No</source> - <translation>No</translation> - </message> - <message> <source>Unknown</source> <translation>Desconocido</translation> </message> @@ -2004,6 +2177,14 @@ <translation>Monto opcional a solicitar. Dejarlo vacío o en cero para no solicitar un monto específico.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Etiqueta opcional para asociar con la nueva dirección de recepción (utilizado por ti para identificar una factura). También esta asociado a la solicitud de pago.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Mensaje opcional asociado a la solicitud de pago que podría ser presentado al remitente </translation> + </message> + <message> <source>&Create new receiving address</source> <translation>Crear nueva dirección para recepción</translation> </message> @@ -2059,56 +2240,60 @@ <source>Copy amount</source> <translation>Copiar cantidad</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>No se pudo desbloquear el monedero.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>No se ha podido generar una nueva dirección %1</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Código QR</translation> - </message> - <message> - <source>Copy &URI</source> - <translation>Copiar &URI</translation> + <source>Request payment to ...</source> + <translation>Solicitar pago a...</translation> </message> <message> - <source>Copy &Address</source> - <translation>Copiar &Dirección</translation> + <source>Address:</source> + <translation>Dirección:</translation> </message> <message> - <source>&Save Image...</source> - <translation>Guardar Imagen...</translation> + <source>Amount:</source> + <translation>Cantidad:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Solicitar pago a %1</translation> + <source>Label:</source> + <translation>Etiqueta:</translation> </message> <message> - <source>Payment information</source> - <translation>Información del pago</translation> + <source>Message:</source> + <translation>Mensaje:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Monedero:</translation> </message> <message> - <source>Address</source> - <translation>Dirección</translation> + <source>Copy &URI</source> + <translation>Copiar &URI</translation> </message> <message> - <source>Amount</source> - <translation>Cantidad</translation> + <source>Copy &Address</source> + <translation>Copiar &Dirección</translation> </message> <message> - <source>Label</source> - <translation>Etiqueta</translation> + <source>&Save Image...</source> + <translation>Guardar Imagen...</translation> </message> <message> - <source>Message</source> - <translation>Mensaje</translation> + <source>Request payment to %1</source> + <translation>Solicitar pago a %1</translation> </message> <message> - <source>Wallet</source> - <translation>Monedero</translation> + <source>Payment information</source> + <translation>Información del pago</translation> </message> </context> <context> @@ -2190,11 +2375,11 @@ </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>Al activarse, si la dirección de cambio está vacía o es inválida, las monedas serán enviadas a una nueva dirección generada.</translation> + <translation>Si se activa, pero la dirección de cambio está vacía o es inválida, las monedas serán enviadas a una nueva dirección generada.</translation> </message> <message> <source>Custom change address</source> - <translation>Dirección propia</translation> + <translation>Dirección de cambio personalizada.</translation> </message> <message> <source>Transaction Fee:</source> @@ -2257,6 +2442,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Polvo:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Esconder ajustes de tarifas de transacción</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Cuando hay menos volumen de transacciones que espacio en los bloques, los mineros y los nodos de retransmisión pueden imponer una comisión mínima. Pagar solo esta comisión mínima está bien, pero tenga en cuenta que esto puede resultar en una transacción nunca confirmada una vez que haya más demanda de transacciones de Bitcoin de la que la red puede procesar.</translation> </message> @@ -2330,7 +2519,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source> from wallet '%1'</source> - <translation>de monedero %1</translation> + <translation>desde el monedero %1</translation> </message> <message> <source>%1 to '%2'</source> @@ -2341,10 +2530,30 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>%1 a %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>¿Desea preparar esta transacción?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>¿Seguro que quiere enviar?</translation> </message> <message> + <source>Create Unsigned</source> + <translation>Crear sin firmar</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Guardar datos de la transacción</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transacción firmaa de manera parcial (Binaria) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT guardado </translation> + </message> + <message> <source>or</source> <translation>o</translation> </message> @@ -2377,10 +2586,18 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Confirmar el envío de monedas</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Confirme la propuesta de transaccion</translation> + </message> + <message> <source>Send</source> <translation>Enviar</translation> </message> <message> + <source>Watch-only balance:</source> + <translation>Visualización unicamente balance:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>La dirección de envío no es válida. Por favor, revísela.</translation> </message> @@ -2398,7 +2615,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Duplicate address found: addresses should only be used once each.</source> - <translation>Dirección duplicada encontrada: la dirección sólo debería ser utilizada una vez por cada uso.</translation> + <translation>Dirección duplicada encontrada: las direcciones sólo deberían ser utilizadas una vez.</translation> </message> <message> <source>Transaction creation failed!</source> @@ -2418,11 +2635,11 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Warning: Invalid Bitcoin address</source> - <translation>Peligro: Dirección de Bitcoin inválida</translation> + <translation>Advertencia: Dirección de Bitcoin inválida.</translation> </message> <message> <source>Warning: Unknown change address</source> - <translation>Peligro: Dirección de cambio desconocida</translation> + <translation>Advertencia: Dirección de cambio desconocida.</translation> </message> <message> <source>Confirm custom change address</source> @@ -2430,7 +2647,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </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>La dirección de cambio seleccionada no es parte de su monedero. Parte de sus fondos serán enviados a esta dirección. ¿Está seguro?</translation> + <translation>La dirección que ha seleccionado para el cambio no es parte de su monedero. Parte o todos sus fondos pueden ser enviados a esta dirección. ¿Está seguro?</translation> </message> <message> <source>(no label)</source> @@ -2476,8 +2693,12 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Eliminar esta entrada.</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>El monto a enviar en las unidades seleccionadas</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>La comisión será deducida de la cantidad que sea enviada. El destinatario recibirá menos bitcoins que la cantidad introducida en el campo Cantidad. Si hay varios destinatarios seleccionados, la comisión será distribuida a partes iguales.</translation> + <translation>La comisión será deducida de la cantidad enviada. El destinatario recibirá menos bitcoins que la cantidad introducida en el campo Cantidad. Si hay varios destinatarios seleccionados, la comisión será distribuida a partes iguales.</translation> </message> <message> <source>S&ubtract fee from amount</source> @@ -2509,7 +2730,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Pay To:</source> - <translation>Paga a:</translation> + <translation>Pagar a:</translation> </message> <message> <source>Memo:</source> @@ -2602,6 +2823,14 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>La dirección Bitcoin con la que se firmó el mensaje</translation> </message> <message> + <source>The signed message to verify</source> + <translation>El mensaje firmado para verificar</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>La firma proporcionada cuando el mensaje fue firmado</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Verificar el mensaje para comprobar que fue firmado con la dirección Bitcoin indicada</translation> </message> @@ -2634,6 +2863,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>El desbloqueo del monedero fue cancelado.</translation> </message> <message> + <source>No error</source> + <translation>Sin error </translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>La llave privada para la dirección introducida no está disponible.</translation> </message> @@ -2817,7 +3050,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </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>Los bitcoins generados deben madurar %1 bloques antes de que puedan gastarse. Cuando generó este bloque, se transmitió a la red para que se añadiera a la cadena de bloques. Si no consigue entrar en la cadena, su estado cambiará a "no aceptado" y ya no se podrá gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque a pocos segundos del suyo.</translation> + <translation>Las monedas generadas deben madurar %1 bloques antes de que puedan gastarse. Cuando generó este bloque, fue retransmitido a la red para que se añadiera a la cadena de bloques. Si no consigue entrar en la cadena, su estado cambiará a "no aceptado" y ya no se podrá gastar. Esto puede ocurrir ocasionalmente si otro nodo genera un bloque a pocos segundos del suyo.</translation> </message> <message> <source>Debug information</source> @@ -2899,7 +3132,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Immature (%1 confirmations, will be available after %2)</source> - <translation>Inmaduro (%1 confirmación(es), Estarán disponibles después de %2)</translation> + <translation>Inmaduro (%1 confirmaciones, Estará disponible después de %2)</translation> </message> <message> <source>Generated but not accepted</source> @@ -3142,12 +3375,28 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Cerrar el monedero durante demasiado tiempo puede causar la resincronización de toda la cadena si la poda es habilitada.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Cerrar todas las carteras</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>¿Está seguro de que desea cerrar todos los monederos?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>No se ha cargado ningún monedero</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>No se ha cargado ningún monedero. +Vaya a Archivo> Abrir monedero para cargar un monedero. +- O -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crear monedero nuevo</translation> </message> </context> <context> @@ -3169,6 +3418,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>¿Desea incrementar la comisión?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>¿Desea preparar una transacción con aumento de comisión ?</translation> + </message> + <message> <source>Current fee:</source> <translation>Comisión actual:</translation> </message> @@ -3185,6 +3438,14 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Confirmar incremento de comisión</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>No se pudo preparar la transacción.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>TBPF copiada</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>No se ha podido firmar la transacción.</translation> </message> @@ -3208,6 +3469,26 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Exportar a un archivo los datos de esta pestaña</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Cargar datos de la transacción</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Transacción firmada de manera parcial (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>El archivo PSBT debe ser más pequeño de 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Imposible descodificar PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Respaldar monedero</translation> </message> @@ -3251,10 +3532,6 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Poda: la última sincronización del monedero sobrepasa los datos podados. Necesita reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Error: Un error interno fatal ha ocurrido. Ver debug.log para detalles</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Poda blockstore...</translation> </message> @@ -3267,12 +3544,8 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Los desarrolladores de %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>No se puede generar una clave de cambio-de-dirección. No hay claves en el conjunto de claves internas y no se pueden generar claves.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation>No se puede bloquear el directorio %s. %s ya se está ejecutando.</translation> + <translation>No se puede bloquear el directorio %s. %s probablemente ya se está ejecutando.</translation> </message> <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> @@ -3300,7 +3573,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> - <translation>Esta es la cuota de transacción que puede descartar si el cambio es más pequeño que el polvo a este nivel.</translation> + <translation>Esta es la comisión por transacción que puede descartar si el cambio es más pequeño que el polvo a este nivel.</translation> </message> <message> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> @@ -3319,20 +3592,12 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Advertencia: ¡No parecemos concordar del todo con nuestros pares! Puede que necesite actualizarse, o puede que otros nodos necesiten actualizarse.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d de los últimos 100 bloques tienen una versión no esperada</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrupto. Fracasó la recuperación</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool debe ser por lo menos de %d MB</translation> </message> <message> <source>Cannot resolve -%s address: '%s'</source> - <translation>No se puede resolver -%s direccion: '%s'</translation> + <translation>No se puede resolver -%s dirección: '%s'</translation> </message> <message> <source>Change index out of range</source> @@ -3351,6 +3616,14 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Corrupción de base de datos de bloques detectada.</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>No se pudo encontrar el archivo asmap %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>No se pudo analizar el archivo asmap %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>¿Quiere reconstruir la base de datos de bloques ahora?</translation> </message> @@ -3368,7 +3641,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Error loading %s: Private keys can only be disabled during creation</source> - <translation>Error cargando %s: Las claves privadas solo pueden ser deshabilitadas durante la creación</translation> + <translation>Error cargando %s: Las llaves privadas solo pueden ser deshabilitadas durante la creación.</translation> </message> <message> <source>Error loading %s: Wallet corrupted</source> @@ -3395,6 +3668,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Fallo al escanear el monedero durante la inicialización</translation> </message> <message> + <source>Failed to verify database</source> + <translation>No se ha podido verificar la base de datos</translation> + </message> + <message> <source>Importing...</source> <translation>Importando...</translation> </message> @@ -3443,10 +3720,6 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Cargando direcciones P2P...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Error: ¡Espacio en disco muy bajo!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Cargando banlist...</translation> </message> @@ -3512,7 +3785,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> - <translation>Cantidad no válida para -maxtxfee=<amount>: '%s' (debe ser por lo menos la comisión mínima de %s para prevenir transacciones atascadas)</translation> + <translation>Cantidad no válida para -maxtxfee=<amount>: '%s' (debe ser al menos la comisión mínima de %s para prevenir transacciones atascadas)</translation> </message> <message> <source>The transaction amount is too small to send after the fee has been deducted</source> @@ -3523,6 +3796,14 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Necesita reconstruir la base de datos utilizando -reindex para volver al modo sin recorte. Esto volverá a descargar toda la cadena de bloques</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Ha ocurrido un error interno grave. Consulte debug.log para más detalles.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>¡El espacio en el disco es demasiado bajo!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Error al leer la base de datos, cerrando la aplicación.</translation> </message> @@ -3555,6 +3836,10 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>Necesita especificar un puerto con -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>No se ha especificado un servidor de proxy. Use -proxy=<ip>o -proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>El modo de poda es incompatible con -blockfilterindex</translation> </message> @@ -3622,17 +3907,13 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Verifying wallet(s)...</source> - <translation>Verificando monedero...</translation> + <translation>Verificando monedero(s)...</translation> </message> <message> <source>Warning: unknown new rules activated (versionbit %i)</source> <translation>Advertencia: nuevas reglas desconocidas activadas (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Eliminando todas las transacciones del monedero...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee tiene un valor muy elevado. Comisiones muy grandes podrían ser pagadas en una única transacción.</translation> </message> @@ -3645,10 +3926,6 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis <translation>La longitud total de la cadena de versión de red ( %i ) supera la longitud máxima ( %i ) . Reducir el número o tamaño de uacomments .</translation> </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>Advertencia: ¡Archivo de monedero corrupto, datos recuperados! Original %s guardado como %s en %s; si su balance de transacciones es incorrecto, debe restaurar desde una copia de seguridad.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>¡%s está configurado muy alto!</translation> </message> @@ -3666,7 +3943,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation>Esta es la tarifa mínima a pagar en cada transacción.</translation> + <translation>Esta es la comisión por transacción mínima a pagar en cada transacción.</translation> </message> <message> <source>This is the transaction fee you will pay if you send a transaction.</source> @@ -3686,17 +3963,13 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation>La red especificada en -onlynet '%s' es desconocida</translation> + <translation>Red desconocida especificada en -onlynet '%s'</translation> </message> <message> <source>Insufficient funds</source> <translation>Fondos insuficientes</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>No se puede actualizar un monedero dividido sin HD sin actualizar para admitir el keypool pre dividido. Utilice -upgradewallet = 169900 o -upgradewallet sin una versión especificada.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Estimación de la comisión fallida. Fallbackfee está deshabilitado. Espere unos pocos bloques o habilite -fallbackfee.</translation> </message> @@ -3718,7 +3991,7 @@ Nota: Dado que la comisión se calcula por byte, una comisión de "100 satoshis </message> <message> <source>Cannot downgrade wallet</source> - <translation>No se puede rebajar el monedero</translation> + <translation>No se puede actualizar a una versión mas antigua el monedero.</translation> </message> <message> <source>Rescanning...</source> diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts index 4b864f4e74..3eb03c966e 100644 --- a/src/qt/locale/bitcoin_es_CL.ts +++ b/src/qt/locale/bitcoin_es_CL.ts @@ -542,11 +542,7 @@ Exportar los datos en la pestaña actual a un archivo</translation> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>La billetera está <b> encriptada </ b> y actualmente está <b> bloqueada </ b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Se produjo un error fatal. Bitcoin ya no puede continuar de manera segura y no continuará</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -956,10 +952,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Muestra si el proxy SOCKS5 suministrado se utiliza para llegar a los pares a través de este tipo de red.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Use SOCKS&5 y proxy por separado para llegar a sus compañeros a través de los servicios ocultos de Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Ocultar el icono de la bandeja del sistema.</translation> </message> @@ -997,7 +989,7 @@ Exportar los datos en la pestaña actual a un archivo</translation> </message> <message> <source>(0 = auto, <0 = leave that many cores free)</source> - <translation>(0 = auto, <0 = deja muchos núcleos gratis)</translation> + <translation>(0 = auto, <0 = deja esta cantidad de núcleos libres)</translation> </message> <message> <source>W&allet</source> @@ -1072,10 +1064,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Conéctese a la red de Bitcoin a través de un proxy SOCKS5 separado para los servicios Tor ocultos.</translation> - </message> - <message> <source>&Window</source> <translation>Ventana</translation> </message> @@ -1246,7 +1234,18 @@ Exportar los datos en la pestaña actual a un archivo</translation> <source>Current total balance in watch-only addresses</source> <translation>Saldo total actual en direcciones de solo reloj</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Cambiar contraseña</translation> + </message> + <message> + <source>or</source> + <translation>o</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1470,10 +1469,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Cadena de bloques</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Número actual de bloques</translation> - </message> - <message> <source>Memory Pool</source> <translation>Grupo de memoria</translation> </message> @@ -1510,10 +1505,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Seleccione un par para ver información detallada.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Incluido en la lista blanca</translation> - </message> - <message> <source>Direction</source> <translation>Dirección</translation> </message> @@ -1550,10 +1541,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Servicios</translation> </message> <message> - <source>Ban Score</source> - <translation>Puntuación Ban</translation> - </message> - <message> <source>Connection Time</source> <translation>Tiempo de conexión</translation> </message> @@ -1694,14 +1681,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Salida</translation> </message> <message> - <source>Yes</source> - <translation>Si</translation> - </message> - <message> - <source>No</source> - <translation>No</translation> - </message> - <message> <source>Unknown</source> <translation>Desconocido</translation> </message> @@ -1780,12 +1759,28 @@ Exportar los datos en la pestaña actual a un archivo</translation> <source>Copy amount</source> <translation>Copiar cantidad</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>No se pudo desbloquear la billetera.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Código QR</translation> + <source>Amount:</source> + <translation>Cantidad:</translation> + </message> + <message> + <source>Label:</source> + <translation>Etiqueta</translation> + </message> + <message> + <source>Message:</source> + <translation>Mensaje:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Billetera:</translation> </message> <message> <source>Copy &URI</source> @@ -1807,30 +1802,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <source>Payment information</source> <translation>Información del pago</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Dirección</translation> - </message> - <message> - <source>Amount</source> - <translation>Cantidad</translation> - </message> - <message> - <source>Label</source> - <translation>Etiqueta</translation> - </message> - <message> - <source>Message</source> - <translation>Mensaje</translation> - </message> - <message> - <source>Wallet</source> - <translation>Billetera</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2715,11 +2686,7 @@ Tarifa de copia</translation> </context> <context> <name>WalletFrame</name> - <message> - <source>No wallet has been loaded.</source> - <translation>No se ha cargado ningún monedero</translation> - </message> -</context> + </context> <context> <name>WalletModel</name> <message> @@ -2775,6 +2742,10 @@ Tarifa de copia</translation> Exportar los datos en la pestaña actual a un archivo</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Respaldar monedero</translation> </message> @@ -2810,10 +2781,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>La Poda se ha configurado por debajo del mínimo de %d MiB. Por favor utiliza un valor mas alto.</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Error: Un error interno fatal ha ocurrido, ver debug.log para detalles</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Poda blockstore...</translation> </message> @@ -2830,14 +2797,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Esta es la cuota de transacción que puede descartar si el cambio es más pequeño que el polvo a este nivel.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d de los últimos 100 bloques tienen una versión no esperada</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrupto. Fracasó la recuperación</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool debe ser por lo menos de %d MB</translation> </message> @@ -3018,10 +2977,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>Advertencia: nuevas reglas desconocidas activadas (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Eliminando todas las transacciones del monedero...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee tiene un valor muy elevado! Comisiones muy grandes podrían ser pagadas en una única transacción.</translation> </message> @@ -3034,10 +2989,6 @@ Exportar los datos en la pestaña actual a un archivo</translation> <translation>La longitud total de la cadena de versión de red ( %i ) supera la longitud máxima ( %i ) . Reducir el número o tamaño de uacomments .</translation> </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>Advertencia: Archivo de monedero corrupto, datos recuperados! Original %s guardado como %s en %s; si su balance de transacciones es incorrecto, debe restaurar desde una copia de seguridad.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>¡%s esta configurado muy alto!</translation> </message> diff --git a/src/qt/locale/bitcoin_es_CO.ts b/src/qt/locale/bitcoin_es_CO.ts index 5c83f25286..fd47d5103f 100644 --- a/src/qt/locale/bitcoin_es_CO.ts +++ b/src/qt/locale/bitcoin_es_CO.ts @@ -537,11 +537,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>La billetera esta <b>codificada</b> y actualmente <b>bloqueda</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Ha ocurrido un error fatal. Bitcoin no puede seguir seguro y se cerrará.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -699,6 +695,10 @@ </context> <context> <name>CreateWalletDialog</name> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Crea una billetera en blanco. Las billeteras en blanco inicialmente no tienen llaves privadas o texto. Las llaves privadas y las direcciones pueden ser importadas, o se puede establecer una semilla HD, más tarde.</translation> + </message> </context> <context> <name>EditAddressDialog</name> @@ -804,6 +804,10 @@ <translation>Al hacer clic OK, %1 iniciará el proceso de descarga y procesará el blockchain completo de %4 (%2 GB), iniciando desde el la transacción más antigua %3 cuando %4 se ejecutó inicialmente.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Revertir esta configuración requiere descargar la blockchain completa nuevamente. Es más rápido descargar la cadena completa y podarla después. Desactiva algunas funciones avanzadas.</translation> + </message> + <message> <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> <translation>El primer proceso de sincronización consume muchos recursos, y es posible que puedan ocurrir problemas de hardware que anteriormente no hayas notado. Cada vez que ejecutes %1 automáticamente se reiniciará el proceso de sincronización desde el punto que lo dejaste anteriormente.</translation> </message> @@ -952,10 +956,6 @@ <translation>Muestra si el proxy SOCKS5 por defecto se utiliza para conectarse a pares a través de este tipo de red.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Use SOCKS&5 y proxy por separado para llegar a sus compañeros a través de los servicios ocultos de Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Ocultar el icono de la bandeja del sistema.</translation> </message> @@ -993,7 +993,7 @@ </message> <message> <source>(0 = auto, <0 = leave that many cores free)</source> - <translation>(0 = auto, <0 = deja muchos núcleos gratis)</translation> + <translation>(0 = auto, <0 = deja esta cantidad de núcleos libres)</translation> </message> <message> <source>W&allet</source> @@ -1068,10 +1068,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Conectar a la red de Bitcoin a través de un proxy SOCKS5 diferente para los servicios anónimos de Tor.</translation> - </message> - <message> <source>&Window</source> <translation>y windows </translation> @@ -1243,7 +1239,14 @@ <source>Current total balance in watch-only addresses</source> <translation>Saldo total actual en direcciones de solo reloj</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>o</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1467,10 +1470,6 @@ <translation>Bloquea cadena</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Cantidad de bloques actual</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memory Pool</translation> </message> @@ -1507,10 +1506,6 @@ <translation>Selecciona un peer para ver la información detallada.</translation> </message> <message> - <source>Whitelisted</source> - <translation>En la lista blanca</translation> - </message> - <message> <source>Direction</source> <translation>Dirección</translation> </message> @@ -1548,10 +1543,6 @@ <translation>Servicios</translation> </message> <message> - <source>Ban Score</source> - <translation>Puntuación de bloqueo</translation> - </message> - <message> <source>Connection Time</source> <translation>Duración de la conexión</translation> </message> @@ -1692,14 +1683,6 @@ <translation>Saliente</translation> </message> <message> - <source>Yes</source> - <translation>Si</translation> - </message> - <message> - <source>No</source> - <translation>No</translation> - </message> - <message> <source>Unknown</source> <translation>Desconocido</translation> </message> @@ -1778,12 +1761,24 @@ <source>Copy amount</source> <translation>Copiar Cantidad</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>No se pudo desbloquear la billetera.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Código QR</translation> + <source>Amount:</source> + <translation>Cantidad:</translation> + </message> + <message> + <source>Message:</source> + <translation>Mensaje:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Billetera:</translation> </message> <message> <source>Copy &URI</source> @@ -1805,30 +1800,6 @@ <source>Payment information</source> <translation>Información del pago</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Dirección</translation> - </message> - <message> - <source>Amount</source> - <translation>Cantidad</translation> - </message> - <message> - <source>Label</source> - <translation>Etiqueta</translation> - </message> - <message> - <source>Message</source> - <translation>Mensaje</translation> - </message> - <message> - <source>Wallet</source> - <translation>Cartera</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2713,11 +2684,7 @@ </context> <context> <name>WalletFrame</name> - <message> - <source>No wallet has been loaded.</source> - <translation>No se ha cargado ningún monedero</translation> - </message> -</context> + </context> <context> <name>WalletModel</name> <message> @@ -2772,6 +2739,10 @@ <translation>Exportar los datos de la pestaña actual a un archivo</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Respaldar monedero</translation> </message> @@ -2807,10 +2778,6 @@ <translation>La Poda se ha configurado por debajo del mínimo de %d MiB. Por favor utiliza un valor mas alto.</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Error: Un error interno fatal ha ocurrido, ver debug.log para detalles</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Poda blockstore...</translation> </message> @@ -2827,14 +2794,6 @@ <translation>Esta es la cuota de transacción que puede descartar si el cambio es más pequeño que el polvo a este nivel.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d de los últimos 100 bloques tienen una versión no esperada</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrupto. Fracasó la recuperación</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool debe ser por lo menos de %d MB</translation> </message> @@ -3015,10 +2974,6 @@ <translation>Advertencia: nuevas reglas desconocidas activadas (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Eliminando todas las transacciones del monedero...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee tiene un valor muy elevado! Comisiones muy grandes podrían ser pagadas en una única transacción.</translation> </message> @@ -3031,10 +2986,6 @@ <translation>La longitud total de la cadena de versión de red ( %i ) supera la longitud máxima ( %i ) . Reducir el número o tamaño de uacomments .</translation> </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>Advertencia: Archivo de monedero corrupto, datos recuperados! Original %s guardado como %s en %s; si su balance de transacciones es incorrecto, debe restaurar desde una copia de seguridad.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>¡%s esta configurado muy alto!</translation> </message> diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts index af7b5189b6..561974f4c8 100644 --- a/src/qt/locale/bitcoin_es_DO.ts +++ b/src/qt/locale/bitcoin_es_DO.ts @@ -407,11 +407,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>La billetera está encriptada y bloqueada recientemente</translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Ha ocurrido un error crítico. Bitcoin ya no puede continuar con seguridad y se cerrará.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -861,6 +857,13 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>o</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -995,10 +998,6 @@ <translation>Cadena de bloques</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Número actual de bloques</translation> - </message> - <message> <source>Last block time</source> <translation>Hora del último bloque</translation> </message> @@ -1081,12 +1080,20 @@ <source>Copy amount</source> <translation>Copiar cantidad</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>No se pudo desbloquear el monedero.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Código QR</translation> + <source>Amount:</source> + <translation>Monto:</translation> + </message> + <message> + <source>Message:</source> + <translation>Mensaje:</translation> </message> <message> <source>Copy &URI</source> @@ -1108,30 +1115,6 @@ <source>Payment information</source> <translation>Información de pago</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Direccion</translation> - </message> - <message> - <source>Amount</source> - <translation>Monto</translation> - </message> - <message> - <source>Label</source> - <translation>Nombre</translation> - </message> - <message> - <source>Message</source> - <translation>Mensaje</translation> - </message> - <message> - <source>Wallet</source> - <translation>Billetera</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -1839,11 +1822,7 @@ </context> <context> <name>WalletFrame</name> - <message> - <source>No wallet has been loaded.</source> - <translation>No se ha cargado ningún monedero</translation> - </message> -</context> + </context> <context> <name>WalletModel</name> <message> @@ -1862,6 +1841,10 @@ <translation>Exportar los datos en la pestaña actual a un archivo</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Respaldo de monedero</translation> </message> diff --git a/src/qt/locale/bitcoin_es_MX.ts b/src/qt/locale/bitcoin_es_MX.ts index acb7f0dc3d..c045a23262 100644 --- a/src/qt/locale/bitcoin_es_MX.ts +++ b/src/qt/locale/bitcoin_es_MX.ts @@ -70,6 +70,12 @@ <translation>Estas son tus direcciones de Bitcoin para enviar pagos. Siempre revisa el monto y la dirección de envío antes de enviar monedas.</translation> </message> <message> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</translation> + </message> + <message> <source>&Copy Address</source> <translation>&Copiar dirección</translation> </message> @@ -132,6 +138,10 @@ <translation>Repita la nueva contraseña</translation> </message> <message> + <source>Show passphrase</source> + <translation>Mostrar contraseña</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Encriptar cartera</translation> </message> @@ -172,6 +182,30 @@ <translation>Cartera encriptada</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Ingresa la nueva frase contraseña para la billetera <br/>Por favor usa una frase contraseña de <b>diez o mas caracteres aleatorios </b>, o <b>ocho o mas palabras</b></translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Ingresa la antigua frase de contraseña y la nueva frase de contraseña para la billetera.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Recuerda que encriptar tu billetera no puede proteger completamente tus bitcoins de ser robadas por malware que haya infectado tu computadora.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Billetera para ser encriptada</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Tu billetera está por ser encriptada</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Tu billetera ha sido encriptada</translation> + </message> + <message> <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> <translation>IMPORTANTE: cualquier copia de seguridad anterior que haya hecho de su archivo de cartera debe ser reemplazada por el archivo de cartera encriptado y recién generado. Por razones de seguridad, las copias de seguridad anteriores del archivo de cartera sin cifrar serán inútiles tan pronto como empieces a usar la nueva billetera encriptada.</translation> </message> @@ -294,6 +328,14 @@ <translation>Abrir &URL...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Crear cartera</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crear una nueva cartera</translation> + </message> + <message> <source>Wallet:</source> <translation>Cartera:</translation> </message> @@ -389,9 +431,45 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) </translation> </message> <message> + <source>Show the list of used sending addresses and labels</source> + <translation>Mostrar la lista de direcciones y etiquetas de envío usadas</translation> + </message> + <message> + <source>Show the list of used receiving addresses and labels</source> + <translation>Mostrar la lista de direcciones y etiquetas de recepción usadas</translation> + </message> + <message> <source>&Command-line options</source> <translation>opciones de la &Linea de comandos</translation> </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n active connection to Bitcoin network</numerusform><numerusform>%n active connections to Bitcoin network</numerusform></translation> + </message> + <message> + <source>Indexing blocks on disk...</source> + <translation>Indexando bloques en el disco...</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Procesando bloques en el disco...</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Processed %n block of transaction history.</numerusform><numerusform>Processed %n blocks of transaction history.</numerusform></translation> + </message> + <message> + <source>%1 behind</source> + <translation>%1 behind</translation> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation>Last received block was generated %1 ago.</translation> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Las transacciones después de esto todavía no serán visibles.</translation> + </message> <message> <source>Error</source> <translation>Error</translation> @@ -409,10 +487,158 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Actualizado al dia </translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Load PSBT from file...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Load Partially Signed Bitcoin Transaction</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Load PSBT from clipboard...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Load Partially Signed Bitcoin Transaction from clipboard</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Open node debugging and diagnostic console</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation>&Sending addresses</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Receiving addresses</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation>Open a bitcoin: URI</translation> + </message> + <message> + <source>Open Wallet</source> + <translation>Abrir Cartera</translation> + </message> + <message> + <source>Open a wallet</source> + <translation>Abrir una cartera</translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>Cerrar Cartera...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>Cerrar cartera</translation> + </message> + <message> + <source>Close All Wallets...</source> + <translation>Close All Wallets...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Close all wallets</translation> + </message> + <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Show the %1 help message to get a list with possible Bitcoin command-line options</translation> + </message> + <message> + <source>&Mask values</source> + <translation>&Mask values</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Mask the values in the Overview tab</translation> + </message> + <message> + <source>default wallet</source> + <translation>cartera predeterminada</translation> + </message> + <message> + <source>No wallets available</source> + <translation>No hay carteras disponibles</translation> + </message> + <message> + <source>&Window</source> + <translation>&Ventana</translation> + </message> + <message> + <source>Minimize</source> + <translation>Minimizar</translation> + </message> + <message> + <source>Zoom</source> + <translation>Zoom</translation> + </message> + <message> + <source>Main Window</source> + <translation>Ventana Principal</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 client</translation> + </message> + <message> + <source>Connecting to peers...</source> + <translation>Conectando con los compañeros...</translation> + </message> + <message> <source>Catching up...</source> <translation>Recibiendo...</translation> </message> <message> + <source>Error: %1</source> + <translation>Error: %1</translation> + </message> + <message> + <source>Warning: %1</source> + <translation>Alerta: %1</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>Fecha: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Amount: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>Wallet: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Type: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Label: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Address: %1 +</translation> + </message> + <message> <source>Sent transaction</source> <translation>Enviar Transacción</translation> </message> @@ -421,6 +647,18 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Transacción entrante</translation> </message> <message> + <source>HD key generation is <b>enabled</b></source> + <translation>HD key generation is <b>enabled</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>HD key generation is <b>disabled</b></translation> + </message> + <message> + <source>Private key <b>disabled</b></source> + <translation>Private key <b>disabled</b></translation> + </message> + <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>La cartera esta <b>encriptada</b> y <b>desbloqueada</b> actualmente </translation> </message> @@ -428,10 +666,22 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>La cartera esta <b>encriptada</b> y <b>bloqueada</b> actualmente </translation> </message> - </context> + <message> + <source>Original message:</source> + <translation>Original message:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>A fatal error occurred. %1 can no longer continue safely and will quit.</translation> + </message> +</context> <context> <name>CoinControlDialog</name> <message> + <source>Coin Selection</source> + <translation>Selección de moneda</translation> + </message> + <message> <source>Quantity:</source> <translation>Cantidad</translation> </message> @@ -448,6 +698,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Cuota:</translation> </message> <message> + <source>Dust:</source> + <translation>Remanente monetario:</translation> + </message> + <message> <source>After Fee:</source> <translation>Después de los cargos por comisión. </translation> </message> @@ -456,14 +710,38 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Cambio</translation> </message> <message> + <source>(un)select all</source> + <translation>(De)seleccionar todo</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Modo árbol </translation> + </message> + <message> + <source>List mode</source> + <translation>Modo lista </translation> + </message> + <message> <source>Amount</source> <translation>Monto</translation> </message> <message> + <source>Received with label</source> + <translation>Recibido con etiqueta</translation> + </message> + <message> + <source>Received with address</source> + <translation>recibido con dirección</translation> + </message> + <message> <source>Date</source> <translation>Fecha</translation> </message> <message> + <source>Confirmations</source> + <translation>Confirmaciones</translation> + </message> + <message> <source>Confirmed</source> <translation>Confirmado </translation> </message> @@ -484,6 +762,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Copiar identificación de la transacción. </translation> </message> <message> + <source>Lock unspent</source> + <translation>Lock unspent</translation> + </message> + <message> + <source>Unlock unspent</source> + <translation>Unlock unspent</translation> + </message> + <message> <source>Copy quantity</source> <translation>Copiar cantidad</translation> </message> @@ -500,10 +786,18 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Copiar bytes</translation> </message> <message> + <source>Copy dust</source> + <translation>Copy dust</translation> + </message> + <message> <source>Copy change</source> <translation>Copiar cambio</translation> </message> <message> + <source>(%1 locked)</source> + <translation>(%1 locked)</translation> + </message> + <message> <source>yes</source> <translation>si</translation> </message> @@ -512,20 +806,88 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>no</translation> </message> <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>Esta capa se vuelve roja si algún destinatario recibe un monto menor al actual limite del remanente monetario </translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Can vary +/- %1 satoshi(s) per input.</translation> + </message> + <message> <source>(no label)</source> <translation>(sin etiqueta)</translation> </message> <message> + <source>change from %1 (%2)</source> + <translation>change from %1 (%2)</translation> + </message> + <message> <source>(change)</source> <translation>cambio</translation> </message> </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Creating Wallet <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>La creación de la cartera falló</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Crear advertencia de cartera</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Crear una cartera </translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Nombre de la cartera </translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Encriptar la cartera. La cartera será encriptada con una frase de contraseña de tu elección.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Encripta la cartera</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Desactivar las llaves privadas de esta cartera. Las carteras con las llaves privadas desactivadas no tendrán llaves privadas y no podrán tener una semilla HD o llaves privadas importadas. Esto es ideal para las carteras "watch-only".</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Desactivar las claves privadas</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Make Blank Wallet</translation> + </message> + <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Use descriptors for scriptPubKey management</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Descriptor Wallet</translation> + </message> + <message> + <source>Create</source> + <translation>Crear</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -537,6 +899,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>&Etiqueta</translation> </message> <message> + <source>The label associated with this address list entry</source> + <translation>La etiqueta asociada a esta entrada de la lista de direcciones</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>La dirección asociada a esta entrada de la lista de direcciones. Esto sólo puede ser modificado para las direcciones de envío.</translation> + </message> + <message> <source>&Address</source> <translation>&Dirección</translation> </message> @@ -553,6 +923,18 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Editar dirección de envío</translation> </message> <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <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>No se puede desbloquear la cartera</translation> </message> @@ -564,10 +946,26 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <context> <name>FreespaceChecker</name> <message> + <source>A new data directory will be created.</source> + <translation>Un nuevo directorio de datos será creado.</translation> + </message> + <message> <source>name</source> <translation>nombre</translation> </message> - </context> + <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation>Directory already exists. Add %1 if you intend to create a new directory here.</translation> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation>El camino ya existe, y no es un directorio.</translation> + </message> + <message> + <source>Cannot create data directory here.</source> + <translation>No se puede crear un directorio de datos aquí.</translation> + </message> +</context> <context> <name>HelpMessageDialog</name> <message> @@ -575,6 +973,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>versión</translation> </message> <message> + <source>About %1</source> + <translation>About %1</translation> + </message> + <message> <source>Command-line options</source> <translation>opciones de la Linea de comandos</translation> </message> @@ -582,27 +984,175 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <context> <name>Intro</name> <message> + <source>Welcome</source> + <translation>Bienvenido</translation> + </message> + <message> + <source>Welcome to %1.</source> + <translation>Welcome to %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>As this is the first time the program is launched, you can choose where %1 will store its data.</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>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.</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Revertir esta configuración requiere descargar nuevamente la cadena de bloques en su totalidad. es mas eficaz descargar la cadena de bloques completa y después reducirla. Desabilitará algunas funciones avanzadas.</translation> + </message> + <message> + <source>This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> + <translation>La sincronización inicial es muy demandante, por lo que algunos problemas en su equipo de computo que no hayan sido detectados pueden verse reflejados. Cada vez que corra al %1, continuará descargando donde se le dejó.</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>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> + </message> + <message> + <source>Use the default data directory</source> + <translation>Usar el directorio de datos predeterminado</translation> + </message> + <message> + <source>Use a custom data directory:</source> + <translation>Usar un directorio de datos customizado:</translation> + </message> + <message> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Discard blocks after verification, except most recent %1 GB (prune)</translation> + </message> + <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>At least %1 GB of data will be stored in this directory, and it will grow over time.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Approximately %1 GB of data will be stored in this directory.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 will download and store a copy of the Bitcoin block chain.</translation> + </message> + <message> + <source>The wallet will also be stored in this directory.</source> + <translation>La cartera también se almacenará en este directorio.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>Error: Specified data directory "%1" cannot be created.</translation> + </message> + <message> <source>Error</source> <translation>Error</translation> </message> - </context> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB of free space available</numerusform><numerusform>%n GB of free space available</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(of %n GB needed)</numerusform><numerusform>(of %n GB needed)</numerusform></translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB needed for full chain)</numerusform><numerusform>(%n GB needed for full chain)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> <source>Form</source> <translation>Formulario</translation> </message> - </context> + <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>Las transacciones recientes pueden no ser visibles todavía, y por lo tanto el saldo de su cartera podría ser incorrecto. Esta información será correcta una vez que su cartera haya terminado de sincronizarse con la red de bitcoin, como se detalla abajo.</translation> + </message> + <message> + <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> + <translation>Los intentos de gastar bitcoins que se vean afectados por transacciones aún no mostradas no serán aceptados por la red.</translation> + </message> + <message> + <source>Number of blocks left</source> + <translation>Número de bloques restantes</translation> + </message> + <message> + <source>Unknown...</source> + <translation>Desconocido...</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>Progress</source> + <translation>Progreso </translation> + </message> + <message> + <source>Progress increase per hour</source> + <translation>Aumento del progreso por hora</translation> + </message> + <message> + <source>calculating...</source> + <translation>calculando...</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation>Tiempo estimado restante hasta la sincronización</translation> + </message> + <message> + <source>Hide</source> + <translation>Ocultar </translation> + </message> + <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Unknown. Syncing Headers (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> - </context> + <message> + <source>Open bitcoin URI</source> + <translation>Abrir la URI de bitcoin</translation> + </message> + <message> + <source>URI:</source> + <translation>URI:</translation> + </message> +</context> <context> <name>OpenWalletActivity</name> - </context> + <message> + <source>Open wallet failed</source> + <translation>Abrir la cartera falló</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Open wallet warning</translation> + </message> + <message> + <source>default wallet</source> + <translation>cartera predeterminada</translation> + </message> + <message> + <source>Opening Wallet <b>%1</b>...</source> + <translation>Opening Wallet <b>%1</b>...</translation> + </message> +</context> <context> <name>OptionsDialog</name> <message> @@ -610,31 +1160,546 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Opciones</translation> </message> <message> + <source>&Main</source> + <translation>&Main</translation> + </message> + <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Automatically start %1 after logging in to the system.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Start %1 on system login</translation> + </message> + <message> + <source>Size of &database cache</source> + <translation>Size of &database cache</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation>Number of script &verification threads</translation> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>IP address of the proxy (e.g. 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>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</translation> + </message> + <message> + <source>Hide the icon from the system tray.</source> + <translation>Hide the icon from the system tray.</translation> + </message> + <message> + <source>&Hide tray icon</source> + <translation>&Hide tray icon</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>Minimizar en lugar de salir de la aplicación cuando la ventana se cierra. Cuando esta opción está activada, la aplicación se cerrará sólo después de seleccionar Salir en el menú.</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>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 |.</translation> + </message> + <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Open the %1 configuration file from the working directory.</translation> + </message> + <message> + <source>Open Configuration File</source> + <translation>Abrir Configuración de Archivo</translation> + </message> + <message> + <source>Reset all client options to default.</source> + <translation>Reset all client options to default.</translation> + </message> + <message> + <source>&Reset Options</source> + <translation>&Reset Options</translation> + </message> + <message> + <source>&Network</source> + <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>MiB</source> + <translation>MiB</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = auto, <0 = leave that many cores free)</translation> + </message> + <message> <source>W&allet</source> <translation>Cartera</translation> </message> <message> + <source>Expert</source> + <translation>Expert</translation> + </message> + <message> + <source>Enable coin &control features</source> + <translation>Enable coin &control features</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>Si usted desactiva el gasto de cambio no confirmado, el cambio de una transacción no puede ser utilizado hasta que esa transacción tenga al menos una confirmación. Esto también afecta la manera en que se calcula su saldo.</translation> + </message> + <message> + <source>&Spend unconfirmed change</source> + <translation>&Gastar el cambio no confirmado</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>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <translation>Map port using &UPnP</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation>Aceptar las conexiones del exterior.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Allow incomin&g connections</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation>Connect to the Bitcoin network through a SOCKS5 proxy.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Connect through SOCKS5 proxy (default 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 of the proxy (e.g. 9050)</translation> + </message> + <message> + <source>Used for reaching peers via:</source> + <translation>Used for reaching peers via:</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>&Ventana</translation> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation>Show only a tray icon after minimizing the window.</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation>&Minimize to the tray instead of the taskbar</translation> + </message> + <message> + <source>M&inimize on close</source> + <translation>M&inimize on close</translation> + </message> + <message> + <source>&Display</source> + <translation>&Display</translation> + </message> + <message> + <source>User Interface &language:</source> + <translation>Idioma de la interfaz de usuario:</translation> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>The user interface language can be set here. This setting will take effect after restarting %1.</translation> + </message> + <message> + <source>&Unit to show amounts in:</source> + <translation>&Unit to show amounts in:</translation> + </message> + <message> + <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> + <translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation> + </message> + <message> + <source>Whether to show coin control features or not.</source> + <translation>Whether to show coin control features or not.</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>&Third party transaction URLs</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Options set in this dialog are overridden by the command line or in the configuration file:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancel</translation> + </message> + <message> + <source>default</source> + <translation>default</translation> + </message> + <message> <source>none</source> <translation>Ninguno </translation> </message> <message> + <source>Confirm options reset</source> + <translation>Confirm options reset</translation> + </message> + <message> + <source>Client restart required to activate changes.</source> + <translation>Client restart required to activate changes.</translation> + </message> + <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>Client will be shut down. Do you want to proceed?</translation> + </message> + <message> + <source>Configuration options</source> + <translation>Configuration options</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>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</translation> + </message> + <message> <source>Error</source> <translation>Error</translation> </message> - </context> + <message> + <source>The configuration file could not be opened.</source> + <translation>The configuration file could not be opened.</translation> + </message> + <message> + <source>This change would require a client restart.</source> + <translation>Este cambio requeriría un reinicio del cliente.</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation>The supplied proxy address is invalid.</translation> + </message> +</context> <context> <name>OverviewPage</name> <message> <source>Form</source> <translation>Formulario</translation> </message> - </context> + <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>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.</translation> + </message> + <message> + <source>Watch-only:</source> + <translation>Watch-only:</translation> + </message> + <message> + <source>Available:</source> + <translation>Available:</translation> + </message> + <message> + <source>Your current spendable balance</source> + <translation>Your current spendable balance</translation> + </message> + <message> + <source>Pending:</source> + <translation>Pending:</translation> + </message> + <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> + </message> + <message> + <source>Immature:</source> + <translation>Immature:</translation> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation>Mined balance that has not yet matured</translation> + </message> + <message> + <source>Balances</source> + <translation>Balances</translation> + </message> + <message> + <source>Total:</source> + <translation>Total:</translation> + </message> + <message> + <source>Your current total balance</source> + <translation>Your current total balance</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>Your current balance in watch-only addresses</translation> + </message> + <message> + <source>Spendable:</source> + <translation>Spendable:</translation> + </message> + <message> + <source>Recent transactions</source> + <translation><b>Transacciones recientes</b></translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Unconfirmed transactions to watch-only addresses</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Mined balance in watch-only addresses that has not yet matured</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Current total balance in watch-only addresses</translation> + </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Sign Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Broadcast Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Copy to Clipboard</translation> + </message> + <message> + <source>Save...</source> + <translation>Save...</translation> + </message> + <message> + <source>Close</source> + <translation>Close</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Failed to load transaction: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Failed to sign transaction: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Could not sign any more inputs.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Signed %1 inputs, but more signatures are still required.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Signed transaction successfully. Transaction is ready to broadcast.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Unknown error processing transaction.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Transaction broadcast successfully! Transaction ID: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Transaction broadcast failed: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT copied to clipboard.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Save Transaction Data</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Partially Signed Transaction (Binary) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT saved to disk.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation> * Sends %1 to %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Unable to calculate transaction fee or total transaction amount.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Pays transaction fee: </translation> + </message> + <message> + <source>Total Amount</source> + <translation>Cantidad total</translation> + </message> + <message> + <source>or</source> + <translation>o</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Transaction has %1 unsigned inputs.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Transaction is missing some information about inputs.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Transaction still needs signature(s).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(But this wallet cannot sign transactions.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(But this wallet does not have the right keys.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Transaction is fully signed and ready for broadcast.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Transaction status is unknown.</translation> + </message> +</context> <context> <name>PaymentServer</name> - </context> + <message> + <source>Payment request error</source> + <translation>Payment request error</translation> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Cannot start bitcoin: click-to-pay handler</translation> + </message> + <message> + <source>URI handling</source> + <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>Cannot process payment request because BIP70 is not supported.</source> + <translation>Cannot process payment request because BIP70 is not supported.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</translation> + </message> + <message> + <source>Invalid payment address %1</source> + <translation>Invalid payment address %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 cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Payment request file handling</translation> + </message> +</context> <context> <name>PeerTableModel</name> - </context> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node/Service</source> + <translation>Node/Service</translation> + </message> + <message> + <source>NodeId</source> + <translation>NodeId</translation> + </message> + <message> + <source>Ping</source> + <translation>Ping</translation> + </message> + <message> + <source>Sent</source> + <translation>Enviado</translation> + </message> + <message> + <source>Received</source> + <translation>Recibido</translation> + </message> +</context> <context> <name>QObject</name> <message> @@ -642,16 +1707,452 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Monto</translation> </message> <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Enter a Bitcoin address (e.g. %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>None</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 second</numerusform><numerusform>%n seconds</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>%n minute</numerusform><numerusform>%n minutes</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n hour</numerusform><numerusform>%n hours</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n day</numerusform><numerusform>%n days</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n week</numerusform><numerusform>%n weeks</numerusform></translation> + </message> + <message> + <source>%1 and %2</source> + <translation>%1 and %2</translation> + </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation><numerusform>%n year</numerusform><numerusform>%n years</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>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> + <message> + <source>Error initializing settings: %1</source> + <translation>Error initializing settings: %1</translation> + </message> + <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 didn't yet exit safely...</translation> + </message> + <message> <source>unknown</source> <translation>desconocido</translation> </message> </context> <context> <name>QRImageWidget</name> - </context> + <message> + <source>&Save Image...</source> + <translation>&Guardar imagen...</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&Copiar Imagen</translation> + </message> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation>Resulting URI too long, try to reduce the text for label / message.</translation> + </message> + <message> + <source>Error encoding URI into QR Code.</source> + <translation>Error codificando la URI en el Código QR.</translation> + </message> + <message> + <source>QR code support not available.</source> + <translation>El soporte del código QR no está disponible.</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>Guardar Código QR</translation> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>PNG imagen (*.png)</translation> + </message> +</context> <context> <name>RPCConsole</name> - </context> + <message> + <source>N/A</source> + <translation>N/A</translation> + </message> + <message> + <source>Client version</source> + <translation>Versión cliente </translation> + </message> + <message> + <source>&Information</source> + <translation>&Información</translation> + </message> + <message> + <source>General</source> + <translation>General</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Using BerkeleyDB version</translation> + </message> + <message> + <source>Datadir</source> + <translation>Datadir</translation> + </message> + <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>To specify a non-default location of the data directory use the '%1' option.</translation> + </message> + <message> + <source>Blocksdir</source> + <translation>Blocksdir</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>To specify a non-default location of the blocks directory use the '%1' option.</translation> + </message> + <message> + <source>Startup time</source> + <translation>Startup time</translation> + </message> + <message> + <source>Network</source> + <translation>Red</translation> + </message> + <message> + <source>Name</source> + <translation>Nombre</translation> + </message> + <message> + <source>Number of connections</source> + <translation>Number of connections</translation> + </message> + <message> + <source>Block chain</source> + <translation>Block chain</translation> + </message> + <message> + <source>Memory Pool</source> + <translation>Memory Pool</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation>Current number of transactions</translation> + </message> + <message> + <source>Memory usage</source> + <translation>Memory usage</translation> + </message> + <message> + <source>Wallet: </source> + <translation>Cartera:</translation> + </message> + <message> + <source>(none)</source> + <translation>(ninguno)</translation> + </message> + <message> + <source>&Reset</source> + <translation>&Reset</translation> + </message> + <message> + <source>Received</source> + <translation>Recibido</translation> + </message> + <message> + <source>Sent</source> + <translation>Enviado</translation> + </message> + <message> + <source>&Peers</source> + <translation>&Peers</translation> + </message> + <message> + <source>Banned peers</source> + <translation>Banned peers</translation> + </message> + <message> + <source>Select a peer to view detailed information.</source> + <translation>Select a peer to view detailed information.</translation> + </message> + <message> + <source>Direction</source> + <translation>Direction</translation> + </message> + <message> + <source>Version</source> + <translation>Version</translation> + </message> + <message> + <source>Starting Block</source> + <translation>Starting Block</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Synced Headers</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Synced Blocks</translation> + </message> + <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>The mapped Autonomous System used for diversifying peer selection.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapped AS</translation> + </message> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</translation> + </message> + <message> + <source>Current block height</source> + <translation>Current block height</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>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>Reducir el tamaño de la letra</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Aumentar el tamaño de la letra</translation> + </message> + <message> + <source>Permissions</source> + <translation>Permissions</translation> + </message> + <message> + <source>Services</source> + <translation>Servicios</translation> + </message> + <message> + <source>Connection Time</source> + <translation>Tiempo de conexión</translation> + </message> + <message> + <source>Last Send</source> + <translation>Último envío</translation> + </message> + <message> + <source>Last Receive</source> + <translation>Última recepción</translation> + </message> + <message> + <source>Ping Time</source> + <translation>Ping Time</translation> + </message> + <message> + <source>The duration of a currently outstanding ping.</source> + <translation>The duration of a currently outstanding ping.</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>Ping Wait</translation> + </message> + <message> + <source>Min Ping</source> + <translation>Min Ping</translation> + </message> + <message> + <source>Time Offset</source> + <translation>Time Offset</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>&Open</source> + <translation>&Open</translation> + </message> + <message> + <source>&Console</source> + <translation>&Console</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation>&Network Traffic</translation> + </message> + <message> + <source>Totals</source> + <translation>Totals</translation> + </message> + <message> + <source>In:</source> + <translation>In:</translation> + </message> + <message> + <source>Out:</source> + <translation>Out:</translation> + </message> + <message> + <source>Debug log file</source> + <translation>Debug log file</translation> + </message> + <message> + <source>Clear console</source> + <translation>Clear console</translation> + </message> + <message> + <source>1 &hour</source> + <translation>1 &hour</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &day</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &week</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &year</translation> + </message> + <message> + <source>&Disconnect</source> + <translation>&Disconnect</translation> + </message> + <message> + <source>Ban for</source> + <translation>Ban for</translation> + </message> + <message> + <source>&Unban</source> + <translation>&Unban</translation> + </message> + <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Welcome to the %1 RPC console.</translation> + </message> + <message> + <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> + <translation>Use up and down arrows to navigate history, and %1 to clear screen.</translation> + </message> + <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Type %1 for an overview of available commands.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>For more information on using this console type %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>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.</translation> + </message> + <message> + <source>Network activity disabled</source> + <translation>Actividad de la red desactivada</translation> + </message> + <message> + <source>Executing command without any wallet</source> + <translation>Ejecutando el comando sin ninguna cartera</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> + <message> + <source>via %1</source> + <translation>via %1</translation> + </message> + <message> + <source>never</source> + <translation>nunca</translation> + </message> + <message> + <source>Inbound</source> + <translation>Entrada</translation> + </message> + <message> + <source>Outbound</source> + <translation>Salida</translation> + </message> + <message> + <source>Unknown</source> + <translation>Desconocido</translation> + </message> +</context> <context> <name>ReceiveCoinsDialog</name> <message> @@ -671,6 +2172,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Mensaje opcional para agregar a la solicitud de pago, el cual será mostrado cuando la solicitud este abierta. Nota: El mensaje no se manda con el pago a travéz de la red de Bitcoin.</translation> </message> <message> + <source>An optional label to associate with the new receiving address.</source> + <translation>Una etiqueta opcional para asociar a la nueva dirección de recepción.</translation> + </message> + <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> <translation>Use este formulario para la solicitud de pagos. Todos los campos son <b>opcionales</b></translation> </message> @@ -679,39 +2184,123 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Monto opcional a solicitar. Dejarlo vacion o en cero no solicita un monto especifico.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Una etiqueta opcional para asociar a la nueva dirección de recepción (utilizada por usted para identificar una factura). También se adjunta a la solicitud de pago.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Un mensaje opcional que se adjunta a la solicitud de pago y que puede mostrarse al remitente.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Crear una nueva dirección de recepción</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Borrar todos los campos del formulario.</translation> + </message> + <message> + <source>Clear</source> + <translation>Borrar </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>Historial de pagos solicitados</translation> + </message> + <message> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation>Mostrar la solicitud seleccionada (hace lo mismo que hacer doble clic en una entrada)</translation> + </message> + <message> + <source>Show</source> + <translation>Mostrar</translation> + </message> + <message> + <source>Remove the selected entries from the list</source> + <translation>Eliminar las entradas seleccionadas de la lista</translation> + </message> + <message> + <source>Remove</source> + <translation>Eliminar </translation> + </message> + <message> + <source>Copy URI</source> + <translation>Copy URI</translation> + </message> + <message> <source>Copy label</source> <translation>Copiar capa </translation> </message> <message> + <source>Copy message</source> + <translation>Copy message</translation> + </message> + <message> <source>Copy amount</source> <translation>copiar monto</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>No se puede desbloquear la cartera</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Could not generate new %1 address</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>&Copiar dirección</translation> + <source>Request payment to ...</source> + <translation>Request payment to ...</translation> </message> <message> - <source>Address</source> - <translation>Dirección</translation> + <source>Address:</source> + <translation>Address:</translation> </message> <message> - <source>Amount</source> - <translation>Monto</translation> + <source>Amount:</source> + <translation>Monto:</translation> </message> <message> - <source>Label</source> - <translation>Etiqueta</translation> + <source>Label:</source> + <translation>Label:</translation> </message> <message> - <source>Message</source> - <translation>Mensaje</translation> + <source>Message:</source> + <translation>Mensaje:</translation> </message> <message> - <source>Wallet</source> - <translation>Cartera</translation> + <source>Wallet:</source> + <translation>Cartera:</translation> + </message> + <message> + <source>Copy &URI</source> + <translation>Copy &URI</translation> + </message> + <message> + <source>Copy &Address</source> + <translation>&Copiar dirección</translation> + </message> + <message> + <source>&Save Image...</source> + <translation>&Guardar imagen...</translation> + </message> + <message> + <source>Request payment to %1</source> + <translation>Request payment to %1</translation> + </message> + <message> + <source>Payment information</source> + <translation>Payment information</translation> </message> </context> <context> @@ -732,7 +2321,19 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <source>(no label)</source> <translation>(sin etiqueta)</translation> </message> - </context> + <message> + <source>(no message)</source> + <translation>(no message)</translation> + </message> + <message> + <source>(no amount requested)</source> + <translation>(no amount requested)</translation> + </message> + <message> + <source>Requested</source> + <translation>Requested</translation> + </message> +</context> <context> <name>SendCoinsDialog</name> <message> @@ -740,6 +2341,22 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Enviar monedas</translation> </message> <message> + <source>Coin Control Features</source> + <translation>Coin Control Features</translation> + </message> + <message> + <source>Inputs...</source> + <translation>Inputs...</translation> + </message> + <message> + <source>automatically selected</source> + <translation>automatically selected</translation> + </message> + <message> + <source>Insufficient funds!</source> + <translation>Insufficient funds!</translation> + </message> + <message> <source>Quantity:</source> <translation>Cantidad</translation> </message> @@ -764,10 +2381,102 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Cambio</translation> </message> <message> + <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source> + <translation>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</translation> + </message> + <message> + <source>Custom change address</source> + <translation>Custom change address</translation> + </message> + <message> + <source>Transaction Fee:</source> + <translation>Transaction Fee:</translation> + </message> + <message> + <source>Choose...</source> + <translation>Choose...</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>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.</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>Warning: Fee estimation is currently not possible.</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> + <message> + <source>Hide</source> + <translation>Ocultar </translation> + </message> + <message> + <source>Recommended:</source> + <translation>Recommended:</translation> + </message> + <message> + <source>Custom:</source> + <translation>Custom:</translation> + </message> + <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(Smart fee not initialized yet. This usually takes a few blocks...)</translation> + </message> + <message> <source>Send to multiple recipients at once</source> <translation>Enviar a múltiples receptores a la vez</translation> </message> <message> + <source>Add &Recipient</source> + <translation>Add &Recipient</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Despeja todos los campos del formulario.</translation> + </message> + <message> + <source>Dust:</source> + <translation>Remanente monetario:</translation> + </message> + <message> + <source>Hide transaction fee settings</source> + <translation>Hide transaction fee settings</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>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.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>A too low fee might result in a never confirming transaction (read the tooltip)</translation> + </message> + <message> + <source>Confirmation time target:</source> + <translation>Confirmation time target:</translation> + </message> + <message> + <source>Enable Replace-By-Fee</source> + <translation>Enable 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>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.</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> <source>Balance:</source> <translation>Saldo:</translation> </message> @@ -776,6 +2485,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Confirme la acción de enviar</translation> </message> <message> + <source>S&end</source> + <translation>S&end</translation> + </message> + <message> <source>Copy quantity</source> <translation>Copiar cantidad</translation> </message> @@ -796,26 +2509,146 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Copiar bytes</translation> </message> <message> + <source>Copy dust</source> + <translation>Copy dust</translation> + </message> + <message> <source>Copy change</source> <translation>Copiar cambio</translation> </message> <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 blocks)</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation>Cr&eate Unsigned</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation> from wallet '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 to '%2'</translation> + </message> + <message> + <source>%1 to %2</source> + <translation>%1 to %2</translation> + </message> + <message> + <source>Do you want to draft this transaction?</source> + <translation>¿Quiere redactar esta transacción?</translation> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation>¿Está seguro de que quiere enviar?</translation> + </message> + <message> + <source>Create Unsigned</source> + <translation>Create Unsigned</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Save Transaction Data</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Partially Signed Transaction (Binary) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT saved</translation> + </message> + <message> <source>or</source> <translation>o</translation> </message> <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</translation> + </message> + <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Por favor, revise su transacción.</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>Cuota de transacción</translation> + </message> + <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Not signalling Replace-By-Fee, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Cantidad total</translation> + </message> + <message> + <source>To review recipient list click "Show Details..."</source> + <translation>Para revisar la lista de destinatarios haga clic en "Mostrar detalles..."</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Confirme para enviar monedas</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Confirmar la propuesta de transacción</translation> + </message> + <message> + <source>Send</source> + <translation>Enviar</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Watch-only balance:</translation> + </message> + <message> + <source>The recipient address is not valid. Please recheck.</source> + <translation>La dirección del destinatario no es válida. Por favor, vuelva a verificarla.</translation> + </message> + <message> <source>The amount to pay must be larger than 0.</source> <translation>El monto a pagar debe ser mayor a 0</translation> </message> <message> + <source>The amount exceeds your balance.</source> + <translation>La cantidad excede su saldo.</translation> + </message> + <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation>The total exceeds your balance when the %1 transaction fee is included.</translation> + </message> + <message> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation>Duplicado de la dirección encontrada: las direcciones sólo deben ser utilizadas una vez cada una.</translation> + </message> + <message> <source>Transaction creation failed!</source> <translation>¡La creación de la transación falló!</translation> </message> <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>A fee higher than %1 is considered an absurdly high fee.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>La solicitud de pago expiró.</translation> + </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Estimated to begin confirmation within %n block.</numerusform><numerusform>Estimated to begin confirmation within %n blocks.</numerusform></translation> + </message> + <message> <source>Warning: Invalid Bitcoin address</source> <translation>Advertencia: Dirección de Bitcoin invalida</translation> </message> @@ -824,6 +2657,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Advertencia: Cambio de dirección desconocido</translation> </message> <message> + <source>Confirm custom change address</source> + <translation>Confirmar la dirección de cambio personalizada</translation> + </message> + <message> + <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source> + <translation>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?</translation> + </message> + <message> <source>(no label)</source> <translation>(sin etiqueta)</translation> </message> @@ -843,6 +2684,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>&Etiqueta</translation> </message> <message> + <source>Choose previously used address</source> + <translation>Elegir la dirección utilizada anteriormente</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>La dirección de Bitcoin para enviar el pago a</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> @@ -859,17 +2708,57 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Quitar esta entrada</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>The amount to send in the selected unit</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>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.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation>S&ubtract fee from amount</translation> + </message> + <message> + <source>Use available balance</source> + <translation>Usar el saldo disponible</translation> + </message> + <message> <source>Message:</source> <translation>Mensaje:</translation> </message> <message> + <source>This is an unauthenticated payment request.</source> + <translation>Esta es una solicitud de pago no autentificada.</translation> + </message> + <message> + <source>This is an authenticated payment request.</source> + <translation>Esta es una solicitud de pago autentificada.</translation> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation>Introducir una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas</translation> + </message> + <message> + <source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source> + <translation>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.</translation> + </message> + <message> <source>Pay To:</source> <translation>Pago para:</translation> </message> - </context> + <message> + <source>Memo:</source> + <translation>Memo:</translation> + </message> +</context> <context> <name>ShutdownWindow</name> <message> + <source>%1 is shutting down...</source> + <translation>%1 is shutting down...</translation> + </message> + <message> <source>Do not shut down the computer until this window disappears.</source> <translation>No apague su computadora hasta que esta ventana desaparesca.</translation> </message> @@ -877,6 +2766,26 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <context> <name>SignVerifyMessageDialog</name> <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Signatures - Sign / Verify a Message</translation> + </message> + <message> + <source>&Sign Message</source> + <translation>&Sign Message</translation> + </message> + <message> + <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <translation>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.</translation> + </message> + <message> + <source>The Bitcoin address to sign the message with</source> + <translation>The Bitcoin address to sign the message with</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Elegir la dirección utilizada anteriormente</translation> + </message> + <message> <source>Alt+A</source> <translation>Alt+A</translation> </message> @@ -889,20 +2798,160 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Alt+P</translation> </message> <message> + <source>Enter the message you want to sign here</source> + <translation>Enter the message you want to sign here</translation> + </message> + <message> <source>Signature</source> <translation>Firma</translation> </message> - </context> + <message> + <source>Copy the current signature to the system clipboard</source> + <translation>Copy the current signature to the system clipboard</translation> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation>Sign the message to prove you own this Bitcoin address</translation> + </message> + <message> + <source>Sign &Message</source> + <translation>Sign &Message</translation> + </message> + <message> + <source>Reset all sign message fields</source> + <translation>Reset all sign message fields</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> + <source>&Verify Message</source> + <translation>&Verify Message</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>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!</translation> + </message> + <message> + <source>The Bitcoin address the message was signed with</source> + <translation>The Bitcoin address the message was signed with</translation> + </message> + <message> + <source>The signed message to verify</source> + <translation>The signed message to verify</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>The signature given when the message was signed</translation> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation>Verify the message to ensure it was signed with the specified Bitcoin address</translation> + </message> + <message> + <source>Verify &Message</source> + <translation>Verify &Message</translation> + </message> + <message> + <source>Reset all verify message fields</source> + <translation>Reset all verify message fields</translation> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation>Click "Sign Message" to generate signature</translation> + </message> + <message> + <source>The entered address is invalid.</source> + <translation>The entered address is invalid.</translation> + </message> + <message> + <source>Please check the address and try again.</source> + <translation>Please check the address and try again.</translation> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation>The entered address does not refer to a key.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation>Wallet unlock was cancelled.</translation> + </message> + <message> + <source>No error</source> + <translation>No error</translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation>Private key for the entered address is not available.</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Message signing failed.</translation> + </message> + <message> + <source>Message signed.</source> + <translation>Message signed.</translation> + </message> + <message> + <source>The signature could not be decoded.</source> + <translation>The signature could not be decoded.</translation> + </message> + <message> + <source>Please check the signature and try again.</source> + <translation>Please check the signature and try again.</translation> + </message> + <message> + <source>The signature did not match the message digest.</source> + <translation>The signature did not match the message digest.</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>Message verification failed.</translation> + </message> + <message> + <source>Message verified.</source> + <translation>Message verified.</translation> + </message> +</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>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Abrir hasta %1</translation> </message> <message> + <source>conflicted with a transaction with %1 confirmations</source> + <translation>conflicted with a transaction with %1 confirmations</translation> + </message> + <message> + <source>0/unconfirmed, %1</source> + <translation>0/unconfirmed, %1</translation> + </message> + <message> + <source>in memory pool</source> + <translation>in memory pool</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>not in memory pool</translation> + </message> + <message> + <source>abandoned</source> + <translation>abandoned</translation> + </message> + <message> <source>%1/unconfirmed</source> <translation>%1/No confirmado</translation> </message> @@ -919,6 +2968,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Fecha</translation> </message> <message> + <source>Source</source> + <translation>Source</translation> + </message> + <message> + <source>Generated</source> + <translation>Generated</translation> + </message> + <message> <source>From</source> <translation>De</translation> </message> @@ -931,10 +2988,50 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Para</translation> </message> <message> + <source>own address</source> + <translation>own address</translation> + </message> + <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> <source>label</source> <translation>etiqueta</translation> </message> <message> + <source>Credit</source> + <translation>Credit</translation> + </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>matures in %n more block</numerusform><numerusform>matures in %n more blocks</numerusform></translation> + </message> + <message> + <source>not accepted</source> + <translation>not accepted</translation> + </message> + <message> + <source>Debit</source> + <translation>Debit</translation> + </message> + <message> + <source>Total debit</source> + <translation>Total debit</translation> + </message> + <message> + <source>Total credit</source> + <translation>Total credit</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>Cuota de transacción</translation> + </message> + <message> + <source>Net amount</source> + <translation>Net amount</translation> + </message> + <message> <source>Message</source> <translation>Mensaje</translation> </message> @@ -947,21 +3044,65 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>ID</translation> </message> <message> + <source>Transaction total size</source> + <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> + <message> + <source> (Certificate was not verified)</source> + <translation> (Certificate was not verified)</translation> + </message> + <message> + <source>Merchant</source> + <translation>Merchant</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>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.</translation> + </message> + <message> + <source>Debug information</source> + <translation>Debug information</translation> + </message> + <message> <source>Transaction</source> <translation>Transacción</translation> </message> <message> + <source>Inputs</source> + <translation>Inputs</translation> + </message> + <message> <source>Amount</source> <translation>Monto</translation> </message> - </context> + <message> + <source>true</source> + <translation>true</translation> + </message> + <message> + <source>false</source> + <translation>false</translation> + </message> +</context> <context> <name>TransactionDescDialog</name> <message> <source>This pane shows a detailed description of the transaction</source> <translation>Este panel muestras una descripción detallada de la transacción</translation> </message> - </context> + <message> + <source>Details for %1</source> + <translation>Details for %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> @@ -976,15 +3117,39 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <source>Label</source> <translation>Etiqueta</translation> </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Abrir hasta %1</translation> </message> <message> + <source>Unconfirmed</source> + <translation>Unconfirmed</translation> + </message> + <message> + <source>Abandoned</source> + <translation>Abandoned</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation>Confirming (%1 of %2 recommended confirmations)</translation> + </message> + <message> <source>Confirmed (%1 confirmations)</source> <translation>Confimado (%1 confirmaciones)</translation> </message> <message> + <source>Conflicted</source> + <translation>Conflicted</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation>Immature (%1 confirmations, will be available after %2)</translation> + </message> + <message> <source>Generated but not accepted</source> <translation>Generado pero no aprovado</translation> </message> @@ -993,6 +3158,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Recibido con</translation> </message> <message> + <source>Received from</source> + <translation>Received from</translation> + </message> + <message> <source>Sent to</source> <translation>Enviar a</translation> </message> @@ -1005,6 +3174,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Minado </translation> </message> <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> <source>(n/a)</source> <translation>(n/a)</translation> </message> @@ -1013,6 +3186,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>(sin etiqueta)</translation> </message> <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation>Transaction status. Hover over this field to show number of confirmations.</translation> + </message> + <message> <source>Date and time that the transaction was received.</source> <translation>Fecha y hora en que la transacción fue recibida </translation> </message> @@ -1021,6 +3198,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Escriba una transacción</translation> </message> <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Whether or not a watch-only address is involved in this transaction.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>User-defined intent/purpose of the transaction.</translation> + </message> + <message> <source>Amount removed from or added to balance.</source> <translation>Cantidad removida del saldo o agregada </translation> </message> @@ -1052,6 +3237,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Este año</translation> </message> <message> + <source>Range...</source> + <translation>Range...</translation> + </message> + <message> <source>Received with</source> <translation>Recibido con</translation> </message> @@ -1072,10 +3261,22 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Otro</translation> </message> <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Enter address, transaction id, or label to search</translation> + </message> + <message> <source>Min amount</source> <translation>Monto minimo </translation> </message> <message> + <source>Abandon transaction</source> + <translation>Abandon transaction</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>Increase transaction fee</translation> + </message> + <message> <source>Copy address</source> <translation>Copiar dirección </translation> </message> @@ -1092,10 +3293,22 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Copiar identificación de la transacción. </translation> </message> <message> + <source>Copy raw transaction</source> + <translation>Copy raw transaction</translation> + </message> + <message> + <source>Copy full transaction details</source> + <translation>Copy full transaction details</translation> + </message> + <message> <source>Edit label</source> <translation>Editar capa </translation> </message> <message> + <source>Show transaction details</source> + <translation>Show transaction details</translation> + </message> + <message> <source>Export Transaction History</source> <translation>Exportar el historial de transacción</translation> </message> @@ -1108,6 +3321,10 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Confirmado </translation> </message> <message> + <source>Watch-only</source> + <translation>Watch-only</translation> + </message> + <message> <source>Date</source> <translation>Fecha</translation> </message> @@ -1144,21 +3361,57 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>el historial de transaciones ha sido guardado exitosamente en %1</translation> </message> <message> + <source>Range:</source> + <translation>Range:</translation> + </message> + <message> <source>to</source> <translation>Para</translation> </message> </context> <context> <name>UnitDisplayStatusBarControl</name> - </context> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Unit to show amounts in. Click to select another unit.</translation> + </message> +</context> <context> <name>WalletController</name> - </context> + <message> + <source>Close wallet</source> + <translation>Cerrar cartera</translation> + </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Are you sure you wish to close the wallet <i>%1</i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Close all wallets</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Are you sure you wish to close all wallets?</translation> + </message> +</context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>No se há cargado la cartera.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crear una nueva cartera</translation> </message> </context> <context> @@ -1167,7 +3420,59 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <source>Send Coins</source> <translation>Enviar monedas</translation> </message> - </context> + <message> + <source>Fee bump error</source> + <translation>Fee bump error</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation>Increasing transaction fee failed</translation> + </message> + <message> + <source>Do you want to increase the fee?</source> + <translation>Do you want to increase the fee?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Do you want to draft a transaction with fee increase?</translation> + </message> + <message> + <source>Current fee:</source> + <translation>Current fee:</translation> + </message> + <message> + <source>Increase:</source> + <translation>Increase:</translation> + </message> + <message> + <source>New fee:</source> + <translation>New fee:</translation> + </message> + <message> + <source>Confirm fee bump</source> + <translation>Confirm fee bump</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Can't draft transaction.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT copied</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Can't sign transaction.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Could not commit transaction</translation> + </message> + <message> + <source>default wallet</source> + <translation>cartera predeterminada</translation> + </message> +</context> <context> <name>WalletView</name> <message> @@ -1179,21 +3484,551 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Exportar la información en la pestaña actual a un archivo</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Unable to decode PSBT from clipboard (invalid base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Load Transaction Data</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Partially Signed Transaction (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PSBT file must be smaller than 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Unable to decode PSBT</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>Backup Wallet</translation> + </message> + <message> + <source>Wallet Data (*.dat)</source> + <translation>Wallet Data (*.dat)</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>Backup Failed</translation> + </message> + <message> <source>There was an error trying to save the wallet data to %1.</source> <translation>Ocurrio un error tratando de guardar la información de la cartera %1</translation> </message> <message> + <source>Backup Successful</source> + <translation>Backup Successful</translation> + </message> + <message> <source>The wallet data was successfully saved to %1.</source> <translation>La información de la cartera fué guardada exitosamente a %1</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>Cancel</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>Distributed under the MIT software license, see the accompanying file %s or %s</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Prune configured below the minimum of %d MiB. Please use a higher number.</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>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Pruning blockstore...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Unable to start HTTP server. See debug log for details.</translation> + </message> + <message> + <source>The %s developers</source> + <translation>The %s developers</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Cannot obtain a lock on data directory %s. %s is probably already running.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Cannot provide specific connections and have addrman find outgoing connections at the same.</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>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</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> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Please contribute if you find %s useful. Visit %s for further information about the software.</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>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</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>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation> + </message> + <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>This is the transaction fee you may discard if change is smaller than dust at this level</translation> + </message> + <message> + <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <translation>Unable to replay blocks. You will need to rebuild the database using -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>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</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>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation> + </message> + <message> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool must be at least %d MB</translation> + </message> + <message> + <source>Cannot resolve -%s address: '%s'</source> + <translation>Cannot resolve -%s address: '%s'</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>Change index out of range</translation> + </message> + <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Config setting for %s only applied on %s network when in [%s] section.</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation>Corrupted block database detected</translation> + </message> + <message> + <source>Could not find asmap file %s</source> + <translation>Could not find asmap file %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Could not parse asmap file %s</translation> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation>Do you want to rebuild the block database now?</translation> + </message> + <message> + <source>Error initializing block database</source> + <translation>Error initializing block database</translation> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation>Error initializing wallet database environment %s!</translation> + </message> + <message> + <source>Error loading %s</source> + <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> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Error loading %s: Wallet requires newer version of %s</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>Error loading block database</translation> + </message> + <message> + <source>Error opening block database</source> + <translation>Error opening block database</translation> + </message> + <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> + </message> + <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Falló al volver a escanear la cartera durante la inicialización</translation> + </message> + <message> + <source>Importing...</source> + <translation>Importando...</translation> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>Initialization sanity check failed. %s is shutting down.</translation> + </message> + <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Invalid P2P permission: '%s'</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Invalid amount for -%s=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -discardfee=<amount>: '%s'</source> + <translation>Invalid amount for -discardfee=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> + <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>Unknown address type '%s'</source> + <translation>Unknown address type '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Unknown change type '%s'</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> + <message> + <source>Loading banlist...</source> + <translation>Cargando la lista de anuncios...</translation> + </message> + <message> + <source>Not enough file descriptors available.</source> + <translation>No hay suficientes descriptores de archivos disponibles.</translation> + </message> + <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Prune cannot be configured with a negative value.</translation> + </message> + <message> + <source>Prune mode is incompatible with -txindex.</source> + <translation>Prune mode is incompatible with -txindex.</translation> + </message> + <message> + <source>Replaying blocks...</source> + <translation>Replaying blocks...</translation> + </message> + <message> + <source>Rewinding blocks...</source> + <translation>Rewinding blocks...</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>The source code is available from %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <translation>La tarifa de la transacción y el cálculo del cambio fallaron</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <translation>Unable to bind to %s on this computer. %s is probably already running.</translation> + </message> + <message> + <source>Unable to generate keys</source> + <translation>Incapaz de generar claves</translation> + </message> + <message> + <source>Unsupported logging category %s=%s.</source> + <translation>Unsupported logging category %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Upgrading UTXO database</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>User Agent comment (%s) contains unsafe characters.</translation> + </message> + <message> <source>Verifying blocks...</source> <translation>Verificando bloques...</translation> </message> <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Wallet needed to be rewritten: restart %s to complete</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Error: Listening for incoming connections failed (listen returned error %s)</translation> + </message> + <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</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>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>La cantidad de la transacción es demasiado pequeña para enviarla después de que se haya deducido la tarifa</translation> + </message> + <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</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>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</translation> + </message> + <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>A fatal internal error occurred, see debug.log for details</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Cannot set -peerblockfilters without -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Disk space is too low!</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Error de lectura de la base de datos, apagando.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Error upgrading chainstate database</translation> + </message> + <message> + <source>Error: Disk space is low for %s</source> + <translation>Error: Disk space is low for %s</translation> + </message> + <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Error: Keypool ran out, please call keypoolrefill first</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Fee rate (%s) is lower than the minimum fee rate setting (%s)</translation> + </message> + <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Invalid -onion address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Invalid -proxy address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Invalid netmask specified in -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Need to specify a port with -whitebind: '%s'</translation> + </message> + <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Prune mode is incompatible with -blockfilterindex.</translation> + </message> + <message> + <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> + <translation>Reducing -maxconnections from %d to %d, because of system limitations.</translation> + </message> + <message> + <source>Section [%s] is not recognized.</source> + <translation>Section [%s] is not recognized.</translation> + </message> + <message> + <source>Signing transaction failed</source> + <translation>La transacción de firma falló</translation> + </message> + <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Specified -walletdir "%s" does not exist</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Specified -walletdir "%s" is a relative path</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Specified -walletdir "%s" is not a directory</translation> + </message> + <message> + <source>The specified config file %s does not exist +</source> + <translation>The specified config file %s does not exist +</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>El monto de la transacción es demasiado pequeño para pagar la tarifa</translation> + </message> + <message> + <source>This is experimental software.</source> + <translation>Este es un software experimental.</translation> + </message> + <message> + <source>Transaction amount too small</source> + <translation>El monto de la transacción es demasiado pequeño</translation> + </message> + <message> + <source>Transaction too large</source> + <translation>La transacción es demasiado grande</translation> + </message> + <message> + <source>Unable to bind to %s on this computer (bind returned error %s)</source> + <translation>Unable to bind to %s on this computer (bind returned error %s)</translation> + </message> + <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>Unable to create the PID file '%s': %s</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>Incapaz de generar claves iniciales</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Unknown -blockfilterindex value %s.</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>Verificando la(s) cartera(s)...</translation> + </message> + <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Warning: unknown new rules activated (versionbit %i)</translation> + </message> + <message> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation> + </message> + <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>Esta es la tarifa de transacción que puede pagar cuando no se dispone de estimaciones de tarifas.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s is set very high!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Error loading wallet %s. Duplicate -wallet filename specified.</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>Starting network threads...</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>The wallet will avoid paying less than the minimum relay fee.</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>Esta es la tarifa de transacción mínima que se paga en cada transacción.</translation> + </message> + <message> + <source>This is the transaction fee you will pay if you send a transaction.</source> + <translation>Esta es la tarifa de transacción que pagará si envía una transacción.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <translation>Los montos de las transacciones no deben ser negativos</translation> + </message> + <message> + <source>Transaction has too long of a mempool chain</source> + <translation>Transaction has too long of a mempool chain</translation> + </message> + <message> + <source>Transaction must have at least one recipient</source> + <translation>La transacción debe tener al menos un destinatario</translation> + </message> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation>Unknown network specified in -onlynet: '%s'</translation> + </message> + <message> + <source>Insufficient funds</source> + <translation>Fondos insuficientes</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>Cargando indice de bloques... </translation> </message> @@ -1202,6 +4037,14 @@ Solicitar pagos (genera códigos QR y bitcoin: URI) <translation>Cargando billetera...</translation> </message> <message> + <source>Cannot downgrade wallet</source> + <translation>Cannot downgrade wallet</translation> + </message> + <message> + <source>Rescanning...</source> + <translation>Rescanning...</translation> + </message> + <message> <source>Done loading</source> <translation>Carga completa</translation> </message> diff --git a/src/qt/locale/bitcoin_es_VE.ts b/src/qt/locale/bitcoin_es_VE.ts index 2dd3247a5f..a216f0f8e0 100644 --- a/src/qt/locale/bitcoin_es_VE.ts +++ b/src/qt/locale/bitcoin_es_VE.ts @@ -132,6 +132,10 @@ <translation>Repita la nueva contraseña</translation> </message> <message> + <source>Show passphrase</source> + <translation>Mostrar la frase de contraseña</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Cifrar monedero</translation> </message> @@ -172,6 +176,14 @@ <translation>Monedero cifrado</translation> </message> <message> + <source>Wallet to be encrypted</source> + <translation>Billetera a ser cifrada</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Su billetera está ahora cifrada</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>IMPORTANTE: Algunas copias de seguridad que hayas hecho de tu archivo de billetera deberían ser reemplazadas con la billetera encriptada generada recientemente. Por razones de seguridad, las copias de seguridad previas del archivo de billetera sin cifrar serán inútiles tan pronto uses la nueva billetera encriptada.</translation> </message> @@ -274,6 +286,18 @@ <translation>Abrir URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Crear Billetera...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crear una nueva billetera</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Actividad de red deshabilitada.</translation> + </message> + <message> <source>Reindexing blocks on disk...</source> <translation>Reindexando bloques en disco...</translation> </message> @@ -386,6 +410,10 @@ <translation>Cerrar monedero</translation> </message> <message> + <source>default wallet</source> + <translation>billetera por defecto</translation> + </message> + <message> <source>No wallets available</source> <translation>Monederos no disponibles</translation> </message> @@ -695,6 +723,10 @@ </context> <context> <name>OpenWalletActivity</name> + <message> + <source>default wallet</source> + <translation>billetera por defecto</translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -867,6 +899,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -961,10 +996,6 @@ <translation>Cadena de bloques</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Número actual de bloques</translation> - </message> - <message> <source>Last block time</source> <translation>Hora del último bloque</translation> </message> @@ -1051,12 +1082,20 @@ <source>Copy amount</source> <translation>Copiar cantidad</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>No se pudo desbloquear la billetera.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Código QR</translation> + <source>Amount:</source> + <translation>Cuantía:</translation> + </message> + <message> + <source>Message:</source> + <translation>Mensaje:</translation> </message> <message> <source>Copy &URI</source> @@ -1070,23 +1109,7 @@ <source>&Save Image...</source> <translation>Guardar Imagen...</translation> </message> - <message> - <source>Address</source> - <translation>Dirección</translation> - </message> - <message> - <source>Amount</source> - <translation>Cantidad</translation> - </message> - <message> - <source>Label</source> - <translation>Etiqueta</translation> - </message> - <message> - <source>Wallet</source> - <translation>Monedero</translation> - </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1457,14 +1480,22 @@ </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Crear una nueva billetera</translation> + </message> +</context> <context> <name>WalletModel</name> <message> <source>Send Coins</source> <translation>Enviar monedas</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation>billetera por defecto</translation> + </message> +</context> <context> <name>WalletView</name> <message> @@ -1476,6 +1507,14 @@ <translation>Exportar a un archivo los datos de esta pestaña</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>Billetera de Respaldo</translation> + </message> + <message> <source>Backup Failed</source> <translation>Copia de seguridad fallida</translation> </message> @@ -1491,7 +1530,11 @@ <source>The wallet data was successfully saved to %1.</source> <translation>Los datos de la billetera fueron guardados exitosamente al %1</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>Cancelar</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index f055141fc3..fc47aec50d 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -132,6 +132,10 @@ <translation>Korda uut parooli</translation> </message> <message> + <source>Show passphrase</source> + <translation>Näita salafraasi</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Krüpteeri rahakott</translation> </message> @@ -172,6 +176,30 @@ <translation>Rahakott krüpteeritud</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Sisesta rahakotile uus salafraas.<br/>Kasuta salafraasi millles on<b>kümme või rohkem juhuslikku sümbolit<b>,või<b>kaheksa või rohkem sõna<b/>.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Sisesta rahakoti vana salafraas ja uus salafraas.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Pea meeles, et rahakoti krüpteerimine ei välista bitcoinide vargust, kui sinu arvuti on nakatunud pahavaraga.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Krüpteeritav rahakott</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Rahakott krüpteeritakse.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Rahakott krüpteeritud.</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>TÄHTIS: Kõik varasemad rahakoti varundfailid tuleks üle kirjutada äsja loodud krüpteeritud rahakoti failiga. Turvakaalutlustel tühistatakse krüpteerimata rahakoti failid alates uue, krüpteeritud rahakoti, kasutusele võtust.</translation> </message> @@ -214,7 +242,11 @@ <source>IP/Netmask</source> <translation>IP/Võrgumask</translation> </message> - </context> + <message> + <source>Banned Until</source> + <translation>Blokeeritud kuni</translation> + </message> +</context> <context> <name>BitcoinGUI</name> <message> @@ -254,6 +286,10 @@ <translation>&Teave %1</translation> </message> <message> + <source>Show information about %1</source> + <translation>Näita informatsiooni %1 kohta</translation> + </message> + <message> <source>About &Qt</source> <translation>Teave &Qt kohta</translation> </message> @@ -266,6 +302,10 @@ <translation>&Valikud...</translation> </message> <message> + <source>Modify configuration options for %1</source> + <translation>Muuda %1 seadeid</translation> + </message> + <message> <source>&Encrypt Wallet...</source> <translation>&Krüpteeri Rahakott</translation> </message> @@ -282,6 +322,18 @@ <translation>Ava &URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Loo rahakott</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Loo uus rahakott</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Rahakott:</translation> + </message> + <message> <source>Reindexing blocks on disk...</source> <translation>Kõvakettal olevate plokkide reindekseerimine...</translation> </message> @@ -455,11 +507,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Rahakott on <b>krüpteeritud</b> ning hetkel <b>suletud</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Ilmnes kriitiline tõrge. Bitcoin suletakse turvakaalutluste tõttu.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -837,6 +885,17 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialoog</translation> + </message> + <message> + <source>or</source> + <translation>või</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -983,10 +1042,6 @@ <translation>Blokiahel</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Plokkide hetkearv</translation> - </message> - <message> <source>Memory usage</source> <translation>Mälu kasutus</translation> </message> @@ -1063,14 +1118,6 @@ <translation>Väljuv</translation> </message> <message> - <source>Yes</source> - <translation>Jah</translation> - </message> - <message> - <source>No</source> - <translation>Ei</translation> - </message> - <message> <source>Unknown</source> <translation>Teadmata</translation> </message> @@ -1113,44 +1160,40 @@ <source>Copy amount</source> <translation>Kopeeri kogus</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Kood</translation> - </message> - <message> - <source>Copy &Address</source> - <translation>&Kopeeri Aadress</translation> + <source>Could not unlock wallet.</source> + <translation>Rahakoti lahtilukustamine ebaõnnestus.</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>&Save Image...</source> - <translation>&Salvesta Pilt...</translation> + <source>Amount:</source> + <translation>Kogus</translation> </message> <message> - <source>Payment information</source> - <translation>Makse Informatsioon</translation> + <source>Label:</source> + <translation>Märgis:</translation> </message> <message> - <source>Address</source> - <translation>Aadress</translation> + <source>Message:</source> + <translation>Sõnum:</translation> </message> <message> - <source>Amount</source> - <translation>Kogus</translation> + <source>Wallet:</source> + <translation>Rahakott:</translation> </message> <message> - <source>Label</source> - <translation>Silt</translation> + <source>Copy &Address</source> + <translation>&Kopeeri Aadress</translation> </message> <message> - <source>Message</source> - <translation>Sõnum</translation> + <source>&Save Image...</source> + <translation>&Salvesta Pilt...</translation> </message> <message> - <source>Wallet</source> - <translation>Rahakott</translation> + <source>Payment information</source> + <translation>Makse Informatsioon</translation> </message> </context> <context> @@ -1851,7 +1894,11 @@ </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Loo uus rahakott</translation> + </message> +</context> <context> <name>WalletModel</name> <message> @@ -1870,6 +1917,10 @@ <translation>Ekspordi kuvatava vahelehe sisu faili</translation> </message> <message> + <source>Error</source> + <translation>Viga</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Varunda Rahakott</translation> </message> diff --git a/src/qt/locale/bitcoin_eu.ts b/src/qt/locale/bitcoin_eu.ts index 7aca604eeb..3d717a5686 100644 --- a/src/qt/locale/bitcoin_eu.ts +++ b/src/qt/locale/bitcoin_eu.ts @@ -70,10 +70,6 @@ <translation>Hauek dira zuk dirua jaso dezaketen Bitcoin helbideak. Egiaztatu beti diru-kopurua eta dirua jasoko duen helbidea zuzen egon daitezen, txanponak bidali baino lehen.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Hauek dira ordainketak jasotzeko zure Bitcoin helbideak. Jaso taulako 'Jasotzeko helbide berri bat sortu' botoia erabili helbide berri bat sortzeko.</translation> - </message> - <message> <source>&Copy Address</source> <translation>&Helbidea kopiatu</translation> </message> @@ -358,6 +354,10 @@ <translation>Blokeak diskoan berriro zerrendatzen...</translation> </message> <message> + <source>Send coins to a Bitcoin address</source> + <translation>Bidali txanponak Bitcoin helbide batera</translation> + </message> + <message> <source>Change the passphrase used for wallet encryption</source> <translation>Diruzorroa enkriptatzeko erabilitako pasahitza aldatu</translation> </message> @@ -382,6 +382,10 @@ <translation>Lehio nagusia erakutsi edo izkutatu</translation> </message> <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Egiaztatu mesua Bitcoin helbide espezifikoarekin erregistratu direla ziurtatzeko</translation> + </message> + <message> <source>&File</source> <translation>&Artxiboa</translation> </message> @@ -406,10 +410,22 @@ <translation>Akatsa</translation> </message> <message> + <source>Information</source> + <translation>Informazioa</translation> + </message> + <message> <source>Up to date</source> <translation>Eguneratua</translation> </message> <message> + <source>&Sending addresses</source> + <translation>&Helbideak bidaltzen</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Helbideak jasotzen</translation> + </message> + <message> <source>Open Wallet</source> <translation>Diruzorroa zabaldu</translation> </message> @@ -426,10 +442,18 @@ <translation>Diruzorroa itxi</translation> </message> <message> + <source>default wallet</source> + <translation>Diruzorro lehenetsia</translation> + </message> + <message> <source>&Window</source> <translation>&Lehioa</translation> </message> <message> + <source>Minimize</source> + <translation>Txikitu</translation> + </message> + <message> <source>Zoom</source> <translation>Gerturatu</translation> </message> @@ -701,6 +725,10 @@ <source>Open wallet warning</source> <translation>Diruzorroa irekitzen abisua</translation> </message> + <message> + <source>default wallet</source> + <translation>Diruzorro lehenetsia</translation> + </message> </context> <context> <name>OptionsDialog</name> @@ -773,6 +801,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -821,28 +852,28 @@ <source>Copy label</source> <translation>Etiketa kopiatu</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Ezin da diruzorroa desblokeatu.</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>&Helbidea kopiatu</translation> - </message> - <message> - <source>Address</source> - <translation>Helbidea</translation> + <source>Amount:</source> + <translation>Kopurua:</translation> </message> <message> - <source>Amount</source> - <translation>Kopurua</translation> + <source>Message:</source> + <translation>Mezua:</translation> </message> <message> - <source>Label</source> - <translation>Izendapen</translation> + <source>Wallet:</source> + <translation>Diruzorroa:</translation> </message> <message> - <source>Message</source> - <translation>Mezua</translation> + <source>Copy &Address</source> + <translation>&Helbidea kopiatu</translation> </message> </context> <context> @@ -1187,14 +1218,22 @@ </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Diruzorro berri bat sortu</translation> + </message> +</context> <context> <name>WalletModel</name> <message> <source>Send Coins</source> <translation>Txanponak bidali</translation> </message> - </context> + <message> + <source>default wallet</source> + <translation>Diruzorro lehenetsia</translation> + </message> +</context> <context> <name>WalletView</name> <message> @@ -1205,6 +1244,10 @@ <source>Export the data in the current tab to a file</source> <translation>Uneko fitxategian datuak esportatu</translation> </message> + <message> + <source>Error</source> + <translation>Akatsa</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index b19bb00160..95d987015d 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -7,7 +7,7 @@ </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> @@ -132,16 +132,20 @@ <translation>رمز/پَس فرِیز را دوباره وارد کنید</translation> </message> <message> + <source>Show passphrase</source> + <translation>نمایش رمز</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> + <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> @@ -165,18 +169,38 @@ </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> - <translation>آیا از رمزگذاری کیفپول خود اطمینان دارید؟</translation> + <translation>آیا از رمزگذاری کیف پول خود اطمینان دارید؟</translation> </message> <message> <source>Wallet encrypted</source> <translation>کیف پول رمزگذاری شده است</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>برای کیف پول خود یک رمز جدید وارد نمائید<br/>لطفاً رمز کیف پول انتخابی را بدین گونه بسازید<b>انتخاب ده ویا بیشتر کاراکتر تصادفی</b> یا <b> حداقل هشت کلمه</b></translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>رمز عبور قدیمی و رمز عبور جدید کیف پول خود را وارد کنید.</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation>والت رمز بندی شد . یاد داشته باشید که پنجره رمز شده نمی تواند کلا از سرقت نرم افزارهای مخرب محافظ کند</translation> </message> <message> + <source>Wallet to be encrypted</source> + <translation>کیف پول رمز نگاری شده است</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>کیف پول شما در حال رمز نگاری می باشد.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>کیف پول شما اکنون رمزنگاری گردیده است.</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> @@ -299,6 +323,14 @@ <translation>بازکردن آدرس...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>ایجاد کیف پول</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>ساخت کیف پول جدید</translation> + </message> + <message> <source>Wallet:</source> <translation>کیف پول:</translation> </message> @@ -447,6 +479,14 @@ <translation>به روز</translation> </message> <message> + <source>Node window</source> + <translation>پنجره گره</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>باز کردن کنسول دی باگ و تشخیص گره</translation> + </message> + <message> <source>&Sending addresses</source> <translation>ادرس ارسال</translation> </message> @@ -455,6 +495,10 @@ <translation>ادرس درسافت</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>بارک کردن یک بیتکوین: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>باز کردن حساب</translation> </message> @@ -463,14 +507,38 @@ <translation>باز کردن یک حساب</translation> </message> <message> + <source>Close Wallet...</source> + <translation>بستن کیف پول...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>کیف پول را ببندید</translation> + </message> + <message> + <source>Close All Wallets...</source> + <translation>همهی کیف پولها را ببند...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>همهی کیف پولها را ببند</translation> + </message> + <message> <source>default wallet</source> <translation>کیف پول پیشفرض</translation> </message> <message> + <source>No wallets available</source> + <translation>هیچ کیف پولی در دسترس نمی باشد</translation> + </message> + <message> <source>&Window</source> <translation>پنجره</translation> </message> <message> + <source>Minimize</source> + <translation>به حداقل رساندن</translation> + </message> + <message> <source>Zoom</source> <translation>بزرگنمایی</translation> </message> @@ -495,6 +563,10 @@ <translation>خطا: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>هشدار: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>تاریخ: %1 @@ -539,6 +611,18 @@ <translation>تراکنش دریافتی</translation> </message> <message> + <source>HD key generation is <b>enabled</b></source> + <translation>تولید کلید HD <b>فعال است</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>تولید کلید HD <b> غیر فعال است</b></translation> + </message> + <message> + <source>Private key <b>disabled</b></source> + <translation>کلید خصوصی <b>غیر فعال </b></translation> + </message> + <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>wallet رمزگذاری شد و در حال حاضر از حالت قفل در آمده است</translation> </message> @@ -547,10 +631,10 @@ <translation>wallet رمزگذاری شد و در حال حاضر قفل است</translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>خطای بحرانی رخ داده است. بیتکوین دیگر به صورت ایمن قادر به ادامه دادن نمیباشد و خارج خواهد شد.</translation> + <source>Original message:</source> + <translation>پیام اصلی:</translation> </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -682,6 +766,10 @@ <translation>خیر</translation> </message> <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>اگر هر گیرنده مقداری کمتر آستانه فعلی دریافت کند از این لیبل قرمز میشود.</translation> + </message> + <message> <source>(no label)</source> <translation>(برچسب ندارد)</translation> </message> @@ -696,10 +784,58 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>در حال ایجاد کیف پول <b> %1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>کیف پول ایجاد نگردید</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>هشدار ایجاد کیف پول</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>ایجاد کیف پول</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>نام کیف پول</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>کیف پول را رمز نگاری نمائید. کیف پول با کلمات رمز انتخاب خودتان رمز نگاری خواهد شد</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>رمز نگاری کیف پول</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>غیر فعال کردن کلیدهای خصوصی برای این کیف پول. کیف پول هایی با کلید های خصوصی غیر فعال هیچ کلید خصوصی نداشته و نمیتوانند HD داشته باشند و یا کلید های خصوصی دارد شدنی داشته باشند. این کیف پول ها صرفاً برای رصد مناسب هستند.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>غیر فعال کردن کلیدهای خصوصی</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>یک کیف پول خالی درست کنید. کیف پول های خالی در ابتدا کلید یا اسکریپت خصوصی ندارند. کلیدها و آدرسهای خصوصی می توانند وارد شوند یا بذر HD را می توان بعداً تنظیم نمود.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>ساخت کیف پول خالی</translation> + </message> + <message> + <source>Create</source> + <translation>ایجاد</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -711,6 +847,14 @@ <translation>برچسب</translation> </message> <message> + <source>The label associated with this address list entry</source> + <translation>برچسب مرتبط با لیست آدرس ورودی</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>برچسب مرتبط با لیست آدرس ورودی می باشد. این می تواند فقط برای آدرس های ارسالی اصلاح شود.</translation> + </message> + <message> <source>&Address</source> <translation>آدرس</translation> </message> @@ -820,6 +964,10 @@ <translation>کیف پول هم در همین دایرکتوری ذخیره میشود.</translation> </message> <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>خطا: نمیتوان پوشهای برای دادهها در «%1» ایجاد کرد.</translation> + </message> + <message> <source>Error</source> <translation>خطا</translation> </message> @@ -870,6 +1018,10 @@ <source>Hide</source> <translation>پنهان کردن</translation> </message> + <message> + <source>Esc</source> + <translation>خروج</translation> + </message> </context> <context> <name>OpenURIDialog</name> @@ -881,6 +1033,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>بازکردن کیف پول به مشکل خورده است</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>هشدار باز کردن کیف پول</translation> + </message> + <message> <source>default wallet</source> <translation>کیف پول پیشفرض</translation> </message> @@ -929,6 +1089,10 @@ <translation>گیگابایت</translation> </message> <message> + <source>MiB</source> + <translation>MiB</translation> + </message> + <message> <source>W&allet</source> <translation>کیف پول</translation> </message> @@ -937,6 +1101,10 @@ <translation>حرفهای</translation> </message> <message> + <source>Enable coin &control features</source> + <translation>فعال کردن قابلیت سکه و کنترل</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>باز کردن خودکار درگاه شبکهٔ بیتکوین روی روترها. تنها زمانی کار میکند که روتر از پروتکل UPnP پشتیبانی کند و این پروتکل فعال باشد.</translation> </message> @@ -977,10 +1145,6 @@ <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> @@ -1141,6 +1305,53 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>تگفتگو</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>کپی کردن</translation> + </message> + <message> + <source>Save...</source> + <translation>ذخیره...</translation> + </message> + <message> + <source>Close</source> + <translation>بستن</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>مشکل نامشخصی در پردازش عملیات رخ داده.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>ذخیره اطلاعات عملیات</translation> + </message> + <message> + <source>Total Amount</source> + <translation>میزان کل</translation> + </message> + <message> + <source>or</source> + <translation>یا</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>عملیات هنوز به امضا(ها) نیاز دارد.</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(اما این کیفپول نمیتواند عملیاتها را امضا کند.)</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>وضعیت عملیات نامشخص است.</translation> + </message> +</context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1166,6 +1377,10 @@ <context> <name>PeerTableModel</name> <message> + <source>User Agent</source> + <translation>نماینده کاربر</translation> + </message> + <message> <source>Node/Service</source> <translation>گره/خدمت</translation> </message> @@ -1277,6 +1492,10 @@ <translation>خطا: %1</translation> </message> <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 به درستی بسته نشد</translation> + </message> + <message> <source>unknown</source> <translation>ناشناس</translation> </message> @@ -1300,6 +1519,10 @@ <translation>خطا در تبدیل نشانی اینترنتی به صورت کد QR.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>پستیبانی از QR کد در دسترس نیست.</translation> + </message> + <message> <source>Save QR Code</source> <translation>ذحیره کردن Qr Code</translation> </message> @@ -1327,10 +1550,18 @@ <translation>عمومی</translation> </message> <message> + <source>Using BerkeleyDB version</source> + <translation>استفاده از نسخه پایگاهداده برکلی</translation> + </message> + <message> <source>Datadir</source> <translation>پوشه داده Datadir</translation> </message> <message> + <source>Blocksdir</source> + <translation>فولدر بلاکها</translation> + </message> + <message> <source>Startup time</source> <translation>زمان آغاز به کار</translation> </message> @@ -1351,10 +1582,6 @@ <translation>زنجیره مجموعه تراکنش ها</translation> </message> <message> - <source>Current number of blocks</source> - <translation>تعداد زنجیره های حاضر</translation> - </message> - <message> <source>Memory Pool</source> <translation>استخر حافظه</translation> </message> @@ -1399,10 +1626,6 @@ <translation>انتخاب همتا یا جفت برای جزییات اطلاعات</translation> </message> <message> - <source>Whitelisted</source> - <translation>لیست سفید شده یا لیست سالم WhiteList</translation> - </message> - <message> <source>Direction</source> <translation>مسیر</translation> </message> @@ -1411,10 +1634,26 @@ <translation>نسخه</translation> </message> <message> + <source>Starting Block</source> + <translation>بلاک اولیه</translation> + </message> + <message> <source>Synced Blocks</source> <translation>بلاکهای همگامسازی شده</translation> </message> <message> + <source>User Agent</source> + <translation>نماینده کاربر</translation> + </message> + <message> + <source>Node window</source> + <translation>پنجره گره</translation> + </message> + <message> + <source>Current block height</source> + <translation>ارتفاع فعلی بلوک</translation> + </message> + <message> <source>Decrease font size</source> <translation>کاهش دادن اندازه فونت</translation> </message> @@ -1531,14 +1770,6 @@ <translation>هیچ وقت</translation> </message> <message> - <source>Yes</source> - <translation>بله</translation> - </message> - <message> - <source>No</source> - <translation>خیر</translation> - </message> - <message> <source>Unknown</source> <translation>ناشناس یا نامعلوم</translation> </message> @@ -1601,56 +1832,56 @@ <source>Copy amount</source> <translation>کپی مقدار</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>کی یو آر کد Qr Code</translation> + <source>Could not unlock wallet.</source> + <translation>نمیتوان کیف پول را باز کرد.</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Copy &URI</source> - <translation>کپی کردن &آدرس URL</translation> + <source>Request payment to ...</source> + <translation>درخواست واریز به ...</translation> </message> <message> - <source>Copy &Address</source> - <translation>کپی آدرس</translation> + <source>Address:</source> + <translation>آدرسها:</translation> </message> <message> - <source>&Save Image...</source> - <translation>&ذخیره کردن تصویر...</translation> + <source>Amount:</source> + <translation>میزان وجه:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>درخواست پرداخت به %1</translation> + <source>Label:</source> + <translation>برچسب:</translation> </message> <message> - <source>Payment information</source> - <translation>اطلاعات پرداخت</translation> + <source>Message:</source> + <translation>پیام:</translation> </message> <message> - <source>URI</source> - <translation>آدرس URL</translation> + <source>Wallet:</source> + <translation>کیف پول:</translation> </message> <message> - <source>Address</source> - <translation>آدرس</translation> + <source>Copy &URI</source> + <translation>کپی کردن &آدرس URL</translation> </message> <message> - <source>Amount</source> - <translation>میزان وجه:</translation> + <source>Copy &Address</source> + <translation>کپی آدرس</translation> </message> <message> - <source>Label</source> - <translation>برچسب</translation> + <source>&Save Image...</source> + <translation>&ذخیره کردن تصویر...</translation> </message> <message> - <source>Message</source> - <translation>پیام</translation> + <source>Request payment to %1</source> + <translation>درخواست پرداخت به %1</translation> </message> <message> - <source>Wallet</source> - <translation>کیف پول</translation> + <source>Payment information</source> + <translation>اطلاعات پرداخت</translation> </message> </context> <context> @@ -1791,6 +2022,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>گرد و غبار یا داست:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>تنظیمات مخفی کردن کارمزد عملیات</translation> + </message> + <message> <source>Confirmation time target:</source> <translation>هدف زمانی تایید شدن:</translation> </message> @@ -1855,6 +2090,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>آیا برای ارسال کردن یا فرستادن مطمئن هستید؟</translation> </message> <message> + <source>Save Transaction Data</source> + <translation>ذخیره اطلاعات عملیات</translation> + </message> + <message> <source>or</source> <translation>یا</translation> </message> @@ -1879,6 +2118,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>تایید کردن ارسال کوین ها</translation> </message> <message> + <source>Send</source> + <translation>ارسال</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>آدرس گیرنده نامعتبر است.لطفا دوباره چک یا بررسی کنید.</translation> </message> @@ -2101,6 +2344,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>قفلگشابی کیفپول لغو شد.</translation> </message> <message> + <source>No error</source> + <translation>بدون خطا</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>کلید خصوصی برای نشانی وارد شده در دسترس نیست.</translation> </message> @@ -2147,6 +2394,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>باز تا %1</translation> </message> <message> + <source>abandoned</source> + <translation>رها شده</translation> + </message> + <message> <source>%1/unconfirmed</source> <translation>%1/تأیید نشده</translation> </message> @@ -2235,6 +2486,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>حجم کل تراکنش</translation> </message> <message> + <source>Merchant</source> + <translation>بازرگان</translation> + </message> + <message> <source>Debug information</source> <translation>اطلاعات دی باگ Debug</translation> </message> @@ -2293,6 +2548,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>تایید نشده</translation> </message> <message> + <source>Abandoned</source> + <translation>رهاشده</translation> + </message> + <message> <source>Confirmed (%1 confirmations)</source> <translation>تأیید شده (%1 تأییدیه)</translation> </message> @@ -2408,6 +2667,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>حداقل میزان وجه</translation> </message> <message> + <source>Abandon transaction</source> + <translation>تراکنش را رها نمائید.</translation> + </message> + <message> <source>Increase transaction fee</source> <translation>افزایش کارمزد تراکنش</translation> </message> @@ -2428,6 +2691,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>کپی شناسه تراکنش</translation> </message> <message> + <source>Copy raw transaction</source> + <translation>معامله اولیه را کپی نمائید.</translation> + </message> + <message> <source>Copy full transaction details</source> <translation>کپی کردن تمامی اطلاعات تراکنش</translation> </message> @@ -2452,6 +2719,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>تایید شده</translation> </message> <message> + <source>Watch-only</source> + <translation>رصد</translation> + </message> + <message> <source>Date</source> <translation>تاریخ</translation> </message> @@ -2493,12 +2764,24 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </context> <context> <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>کیف پول را ببندید</translation> + </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>آیا برای بستن کیف پول مطمئن هستید<i> %1 </i> ؟</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>همهی کیف پولها را ببند</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>کیفپولی بارگذاری نشد.</translation> + <source>Create a new wallet</source> + <translation>ساخت کیف پول جدید</translation> </message> </context> <context> @@ -2528,6 +2811,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>کارمزد جدید:</translation> </message> <message> + <source>PSBT copied</source> + <translation>PSBT کپی شد</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>نمیتوان تراکنش را ثبت کرد</translation> </message> @@ -2547,6 +2834,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>صدور داده نوار جاری به یک فایل</translation> </message> <message> + <source>Error</source> + <translation>خطا</translation> + </message> + <message> <source>Backup Wallet</source> <translation>بازیابی یا پشتیبان گیری کیف پول</translation> </message> @@ -2638,6 +2929,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>توصیفگرهای فایل به اندازه کافی در دسترس نیست</translation> </message> <message> + <source>Replaying blocks...</source> + <translation>در حال بازبینی بلوکها...</translation> + </message> + <message> <source>The source code is available from %s.</source> <translation>سورس کد موجود است از %s.</translation> </message> @@ -2662,6 +2957,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>خواندن از پایگاه داده با خطا مواجه شد,در حال خاموش شدن.</translation> </message> <message> + <source>Error upgrading chainstate database</source> + <translation>خطا در بارگذاری پایگاه داده ها</translation> + </message> + <message> <source>Invalid -proxy address or hostname: '%s'</source> <translation>آدرس پراکسی یا هاست نامعتبر: ' %s'</translation> </message> @@ -2698,11 +2997,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>هشدار: قوانین جدید ناشناختهای فعال شدهاند (نسخهبیت %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>تراکنش بیش از حد طولانی از یک زنجیر مهر و موم شده است -</translation> - </message> - <message> <source>This is the transaction fee you may pay when fee estimates are not available.</source> <translation>این هزینه تراکنشی است که در صورت عدم وجود هزینه تخمینی، پرداخت می کنید.</translation> </message> diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts index 28b455d13c..6d5d9c9e2e 100644 --- a/src/qt/locale/bitcoin_fi.ts +++ b/src/qt/locale/bitcoin_fi.ts @@ -70,8 +70,10 @@ <translation>Nämä ovat Bitcoin-osoitteesi maksujen lähettämistä varten. Tarkista aina määrä ja vastaanotto-osoite ennen kolikoiden lähettämistä.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Nämä ovat sinun Bitcoin osoitteesi maksujen vastaanottamista varten. Käytä 'Luo uusi vastaanotto-osoite' painiketta vastaantto tabissä luodaksesi uuden osoitteen.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Nämä ovat Bitcoin-osoitteesi maksujen vastaanottoa varten. Käytä painiketta "Luo uusi vastaanotto-osoite" vastaanottovälilehdessä luodaksesi uusia osoitteita. +Allekirjoitus on mahdollista vain 'legacy'-tyyppisillä osoitteilla.</translation> </message> <message> <source>&Copy Address</source> @@ -482,6 +484,30 @@ <translation>Rahansiirtohistoria on ajan tasalla</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Lataa PSBT (osittain allekirjoitettu bitcoin-siirto) tiedostosta...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Lataa osittain allekirjoitettu bitcoin-siirtotapahtuma</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Lataa PSBT (osittain allekirjoitettu bitcoin-siirto) leikepöydältä...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Lataa osittain allekirjoitettu bitcoin-siirtotapahtuma leikepöydältä</translation> + </message> + <message> + <source>Node window</source> + <translation>Solmu ikkuna</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Avaa solmun diagnostiikka- ja vianmäärityskonsoli </translation> + </message> + <message> <source>&Sending addresses</source> <translation>&Lähetysosoitteet</translation> </message> @@ -490,6 +516,10 @@ <translation>&Vastaanotto-osoitteet</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Avaa bitcoin: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Avaa lompakko</translation> </message> @@ -506,10 +536,26 @@ <translation>Sulje lompakko</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Sulje kaikki lompakot...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Sulje kaikki lompakot</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Näytä %1 ohjeet saadaksesi listan mahdollisista Bitcoinin komentorivivalinnoista</translation> </message> <message> + <source>&Mask values</source> + <translation>&Naamioi arvot</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Naamioi arvot Yhteenveto-välilehdessä</translation> + </message> + <message> <source>default wallet</source> <translation>oletuslompakko</translation> </message> @@ -618,8 +664,12 @@ <translation>Lompakko on <b>salattu</b> ja tällä hetkellä <b>lukittuna</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Peruuttamaton virhe on tapahtunut. Bitcoin ei voi enää jatkaa turvallisesti ja sammutetaan.</translation> + <source>Original message:</source> + <translation>Alkuperäinen viesti:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Peruuttamaton virhe on tapahtunut. %1 ei voi enää jatkaa turvallisesti ja sammutetaan.</translation> </message> </context> <context> @@ -783,7 +833,11 @@ <source>Create wallet failed</source> <translation>Lompakon luonti epäonnistui</translation> </message> - </context> + <message> + <source>Create wallet warning</source> + <translation>Luo lompakkovaroitus</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> <message> @@ -803,6 +857,10 @@ <translation>Salaa lompakko</translation> </message> <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Poista tämän lompakon yksityiset avaimet käytöstä. Lompakot, joissa yksityiset avaimet on poistettu käytöstä, eivät sisällä yksityisiä avaimia, eikä niissä voi olla HD-juurisanoja tai tuotuja yksityisiä avaimia. Tämä on ihanteellinen katselulompakkoihin.</translation> + </message> + <message> <source>Disable Private Keys</source> <translation>Poista yksityisavaimet käytöstä</translation> </message> @@ -815,6 +873,14 @@ <translation>Luo tyhjä lompakko</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Käytä kuvaajia sciptPubKeyn hallinnointiin</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Kuvaajalompakko</translation> + </message> + <message> <source>Create</source> <translation>Luo</translation> </message> @@ -1042,6 +1108,14 @@ <translation>Piilota</translation> </message> <message> + <source>Esc</source> + <translation>Poistu</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 synkronoidaan parhaillaan. Se lataa tunnisteet ja lohkot vertaisilta ja vahvistaa ne, kunnes ne saavuttavat lohkon ketjun kärjen.</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Tuntematon. Synkronoidaan tunnisteita (%1, %2%)...</translation> </message> @@ -1049,6 +1123,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Avaa bitcoin URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1060,6 +1138,10 @@ <translation>Lompakon avaaminen epäonnistui</translation> </message> <message> + <source>Open wallet warning</source> + <translation>Avoimen lompakon varoitus</translation> + </message> + <message> <source>default wallet</source> <translation>oletuslompakko</translation> </message> @@ -1103,10 +1185,6 @@ <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> @@ -1239,10 +1317,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Yhdistä Bitcoin-verkkoon erillisen SOCKS5-välityspalvelimen kautta piilotettuja Tor-palveluja varten.</translation> - </message> - <message> <source>&Window</source> <translation>&Ikkuna</translation> </message> @@ -1283,6 +1357,14 @@ <translation>Näytetäänkö kolikkokontrollin ominaisuuksia vai ei</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Yhdistä Bitcoin-verkkoon erillisen SOCKS5-välityspalvelimen kautta Torin onion-palveluja varten.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Käytä erillistä SOCKS&5-välityspalvelinta tavoittaaksesi vertaisia Torin onion-palvelujen kautta:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&Kolmannen osapuolen rahansiirto URL:t</translation> </message> @@ -1417,6 +1499,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Nykyinen tase seurattavassa osoitetteissa</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Yksityisyysmoodi aktivoitu Yhteenveto-välilehdestä. Paljastaaksesi arvot raksi pois Asetukset->Naamioi arvot.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialogi</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Allekirjoita Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Lähetä Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Kopioi leikepöydälle</translation> + </message> + <message> + <source>Save...</source> + <translation>Tallenna...</translation> + </message> + <message> + <source>Close</source> + <translation>Sulje</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Siirtoa ei voitu ladata: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Siirtoa ei voitu allekirjoittaa: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Syötteitä ei voitu enää allekirjoittaa.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>%1 syötettä allekirjoitettiin, mutta lisää allekirjoituksia tarvitaan.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Siirto allekirjoitettiin onnistuneesti. Siirto on valmis lähetettäväksi.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Siirron käsittelyssä tapahtui tuntematon virhe.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Siirto lähetettiin onnistuneesti! Siirtotunniste: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Siirron lähetys epäonnstui: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT (osittain allekirjoitettu bitcoin-siirto) kopioitiin leikepöydälle.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Tallenna siirtotiedot</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Osittain tallennettu siirto (binääri) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT (osittain tallennettu bitcoin-siirto) tallennettiin levylle.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>*Lähettää %1'n kohteeseen %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Siirtokuluja tai siirron lopullista määrää ei voitu laskea.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Maksaa siirtokulut:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Yhteensä</translation> + </message> + <message> + <source>or</source> + <translation>tai</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Siirrossa on %1 allekirjoittamatonta syötettä.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Siirto kaipaa tietoa syötteistä.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Siirto tarvitsee vielä allekirjoituksia.</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Mutta tämä lompakko ei voi allekirjoittaa siirtoja.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Mutta tällä lompakolla ei ole oikeita avaimia.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Siirto on täysin allekirjoitettu ja valmis lähetettäväksi.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Siirron tila on tuntematon.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1437,6 +1646,14 @@ <translation>'bitcoin://' ei ole kelvollinen URI. Käytä 'bitcoin:' sen sijaan.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Maksupyyntöä ei voida käsitellä, koska BIP70:tä ei tueta.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>BIP70:n laajalle levinneiden tietoturvavirheiden vuoksi on erittäin suositeltavaa, että kaikki kauppiaan ohjeet lompakkojen vaihtamiseksi jätetään huomioimatta.</translation> + </message> + <message> <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> <translation>Tämän virheen saadessasi tulee sinun pyytää kauppiaalta BIP21 -yhteensopivaa URI-osoitetta.</translation> </message> @@ -1575,6 +1792,10 @@ <translation>Virhe: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Virhe alustaessa asetuksia: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 ei vielä sulkeutunut turvallisesti...</translation> </message> @@ -1673,10 +1894,6 @@ <translation>Lohkoketju</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Nykyinen Lohkojen määrä</translation> - </message> - <message> <source>Memory Pool</source> <translation>Muistiallas</translation> </message> @@ -1721,10 +1938,6 @@ <translation>Valitse vertainen eriteltyjä tietoja varten.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Sallittu</translation> - </message> - <message> <source>Direction</source> <translation>Suunta</translation> </message> @@ -1745,10 +1958,26 @@ <translation>Synkronoidut lohkot</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Kartoitettu autonominen järjestelmä, jota käytetään monipuolistamaan solmuvalikoimaa</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Kartoitettu AS</translation> + </message> + <message> <source>User Agent</source> <translation>Käyttöliittymä</translation> </message> <message> + <source>Node window</source> + <translation>Solmun näkymä</translation> + </message> + <message> + <source>Current block height</source> + <translation>Lohkon nykyinen korkeus</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>Avaa %1 -debug-loki tämänhetkisestä data-hakemistosta. Tämä voi viedä muutaman sekunnin suurille lokitiedostoille.</translation> </message> @@ -1761,12 +1990,12 @@ <translation>Suurenna fontin kokoa</translation> </message> <message> - <source>Services</source> - <translation>Palvelut</translation> + <source>Permissions</source> + <translation>Luvat</translation> </message> <message> - <source>Ban Score</source> - <translation>Panna-pisteytys</translation> + <source>Services</source> + <translation>Palvelut</translation> </message> <message> <source>Connection Time</source> @@ -1917,14 +2146,6 @@ <translation>Ulosmenevä</translation> </message> <message> - <source>Yes</source> - <translation>Kyllä</translation> - </message> - <message> - <source>No</source> - <translation>Ei</translation> - </message> - <message> <source>Unknown</source> <translation>Tuntematon</translation> </message> @@ -1960,6 +2181,18 @@ <translation>Valinnainen pyyntömäärä. Jätä tyhjäksi tai nollaksi jos et pyydä tiettyä määrää.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Valinnainen tarra, joka liitetään uuteen vastaanotto-osoitteeseen (jonka käytät laskun tunnistamiseen). Se liitetään myös maksupyyntöön.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Valinnainen viesti, joka on liitetty maksupyyntöön ja joka voidaan näyttää lähettäjälle.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation> &Luo uusi vastaanotto-osoite</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>Tyhjennä lomakkeen kaikki kentät.</translation> </message> @@ -2011,56 +2244,60 @@ <source>Copy amount</source> <translation>Kopioi määrä</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Lompakkoa ei voitu avata.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Uutta %1-osoitetta ei voitu luoda</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-koodi</translation> + <source>Request payment to ...</source> + <translation>Pyydä maksua osoitteeseen...</translation> </message> <message> - <source>Copy &URI</source> - <translation>Kopioi &URI</translation> + <source>Address:</source> + <translation>Osoite:</translation> </message> <message> - <source>Copy &Address</source> - <translation>Kopioi &Osoite</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>&Tallenna kuva</translation> + <source>Amount:</source> + <translation>Määrä:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Pyydä maksua osoitteeseen %1</translation> + <source>Label:</source> + <translation>Tunniste:</translation> </message> <message> - <source>Payment information</source> - <translation>Maksutiedot</translation> + <source>Message:</source> + <translation>Viesti:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Lompakko:</translation> </message> <message> - <source>Address</source> - <translation>Osoite</translation> + <source>Copy &URI</source> + <translation>Kopioi &URI</translation> </message> <message> - <source>Amount</source> - <translation>Määrä</translation> + <source>Copy &Address</source> + <translation>Kopioi &Osoite</translation> </message> <message> - <source>Label</source> - <translation>Nimike</translation> + <source>&Save Image...</source> + <translation>&Tallenna kuva</translation> </message> <message> - <source>Message</source> - <translation>Viesti</translation> + <source>Request payment to %1</source> + <translation>Pyydä maksua osoitteeseen %1</translation> </message> <message> - <source>Wallet</source> - <translation>Lompakko</translation> + <source>Payment information</source> + <translation>Maksutiedot</translation> </message> </context> <context> @@ -2209,6 +2446,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Tomu:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation> Piilota siirtomaksuasetukset</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Mikäli lohkoissa ei ole tilaa kaikille siirtotapahtumille, voi louhijat sekä välittävät solmut pakottaa vähimmäispalkkion. Tämän vähimmäispalkkion maksaminen on täysin OK, mutta huomaa, että se saattaa johtaa siihen, ettei siirto vahvistu koskaan, jos bitcoin-siirtoja on enemmän kuin mitä verkko pystyy käsittelemään.</translation> </message> @@ -2277,6 +2518,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>%1 (%2 lohkoa)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>L&uo allekirjoittamaton</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Luo osittain allekirjoitetun bitcoin-siirtotapahtuman (PSBT) käytettäväksi mm. offline %1 lompakko tai PSBT-yhteensopiva hardware-lompakko.</translation> + </message> + <message> <source> from wallet '%1'</source> <translation> lompakosta '%1'</translation> </message> @@ -2285,10 +2534,30 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>%1 to %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Haluatko laatia tämän siirron?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Oletko varma, että haluat lähettää?</translation> </message> <message> + <source>Create Unsigned</source> + <translation>Luo allekirjoittamaton</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Tallenna siirtotiedot</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Osittain tallennettu siirtotapahtuma (binääri) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT tallennettu</translation> + </message> + <message> <source>or</source> <translation>tai</translation> </message> @@ -2297,6 +2566,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Voit korottaa palkkiota myöhemmin (osoittaa Replace-By-Fee:tä, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Ole hyvä ja tarkista siirtoehdotuksesi. Tämä luo osittain allekirjoitetun Bitcoin-siirron (PBST), jonka voit tallentaa tai kopioida ja sitten allekirjoittaa esim. verkosta irrannaisella %1-lompakolla tai PBST-yhteensopivalla laitteistolompakolla.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Tarkistathan siirtosi.</translation> </message> @@ -2305,6 +2578,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Siirtokulu</translation> </message> <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Ei signalointia Korvattavissa korkeammalla kululla, BIP-125.</translation> + </message> + <message> <source>Total Amount</source> <translation>Yhteensä</translation> </message> @@ -2317,6 +2594,18 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Vahvista kolikoiden lähetys</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Vahvista siirtoehdotus</translation> + </message> + <message> + <source>Send</source> + <translation>Lähetä</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Katselulompakon saldo:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Vastaanottajan osoite ei ole kelvollinen. Tarkista osoite.</translation> </message> @@ -2412,6 +2701,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Poista tämä alkio</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Lähetettävä summa valitussa yksikössä</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>Kulu vähennetään lähetettävästä määrästä. Saaja vastaanottaa vähemmän bitcoineja kuin merkitset Määrä-kenttään. Jos saajia on monia, kulu jaetaan tasan.</translation> </message> @@ -2538,6 +2831,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Bitcoin-osoite jolla viesti on allekirjoitettu</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Allekirjoitettu viesti vahvistettavaksi</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>Viestin allekirjoittamisen yhteydessä annettu allekirjoitus</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Tarkista viestin allekirjoitus varmistaaksesi, että se allekirjoitettiin tietyllä Bitcoin-osoitteella</translation> </message> @@ -2570,6 +2871,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Lompakon avaaminen peruttiin.</translation> </message> <message> + <source>No error</source> + <translation>Ei virhettä</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Yksityistä avainta syötetylle osoitteelle ei ole saatavilla.</translation> </message> @@ -2740,6 +3045,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Tapahtuman näennäiskoko</translation> </message> <message> + <source>Output index</source> + <translation>Ulostulon indeksi</translation> + </message> + <message> + <source> (Certificate was not verified)</source> + <translation> (Sertifikaattia ei vahvistettu)</translation> + </message> + <message> <source>Merchant</source> <translation>Kauppias</translation> </message> @@ -3066,12 +3379,28 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Lompakon sulkeminen liian pitkäksi aikaa saattaa johtaa tarpeeseen synkronoida koko ketju uudelleen, mikäli karsinta on käytössä.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Sulje kaikki lompakot</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Haluatko varmasti sulkea kaikki lompakot?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Lomakkoa ei ole ladattu.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Lompakkoa ei ladattu. +Siirry osioon Tiedosto > Avaa lompakko ladataksesi lompakon. +- TAI -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Luo uusi lompakko</translation> </message> </context> <context> @@ -3093,6 +3422,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Haluatko nostaa siirtomaksua?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Haluatko nostaa siirtomaksua siirtoon?</translation> + </message> + <message> <source>Current fee:</source> <translation>Nykyinen palkkio:</translation> </message> @@ -3109,6 +3442,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Vahvista palkkion korotus</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation> Siirtoa ei voida laatia.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT kopioitu</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Siirtoa ei voida allekirjoittaa.</translation> </message> @@ -3132,6 +3473,30 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Vie auki olevan välilehden tiedot tiedostoon</translation> </message> <message> + <source>Error</source> + <translation>Virhe</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>PBST-ää ei voitu tulkita leikepöydältä (kelpaamaton base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Lataa siirtotiedot</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Osittain allekirjoitettu siirto (*.pbst)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PBST-tiedoston tulee olla pienempi kuin 100 mebitavua</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>PSBT-ää ei voitu tulkita</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Varmuuskopioi lompakko</translation> </message> @@ -3175,10 +3540,6 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Karsinta: viime lompakon synkronisointi menee karsitun datan taakse. Sinun tarvitsee ajaa -reindex (lataa koko lohkoketju uudelleen tapauksessa jossa karsiva noodi)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Virhe: Kriittinen sisäinen virhe kohdattiin, katso debug.log lisätietoja varten</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Karsitaan lohkovarastoa...</translation> </message> @@ -3191,18 +3552,22 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>%s kehittäjät</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Vaihtorahaosoitetta ei voida luoda. Sisäisessä varannossa ei ole avaimia, eikä uusia avaimia voida luoda.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Ei voida lukita data-hakemistoa %s. %s on luultavasti jo käynnissä.</translation> </message> <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Ei voida tarjota tiettyjä yhteyksiä, ja antaa addrmanin löytää lähteviä yhteyksiä samanaikaisesti.</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>Virhe luettaessa %s! Avaimet luetttiin oikein, mutta rahansiirtotiedot tai osoitekirjan sisältö saattavat olla puutteellisia tai vääriä.</translation> </message> <message> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation>Useampi onion bind -osoite on tarjottu. Automaattisesti luotua Torin onion-palvelua varten käytetään %s.</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Tarkistathan että tietokoneesi päivämäärä ja kellonaika ovat oikeassa! Jos kellosi on väärässä, %s ei toimi oikein.</translation> </message> @@ -3211,6 +3576,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Ole hyvä ja avusta, jos %s on mielestäsi hyödyllinen. Vieraile %s saadaksesi lisää tietoa ohjelmistosta.</translation> </message> <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: Lausekkeen valmistelu sqlite-lompakkokaavioversion %s noutamista varten epäonnistui</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>SQLiteDatabase: Lausekkeen valmistelu sovellustunnisteen %s noutamista varten epäonnistui</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>Lohkotietokanta sisältää lohkon, joka vaikuttaa olevan tulevaisuudesta. Tämä saattaa johtua tietokoneesi virheellisesti asetetuista aika-asetuksista. Rakenna lohkotietokanta uudelleen vain jos olet varma, että tietokoneesi päivämäärä ja aika ovat oikein.</translation> </message> @@ -3239,14 +3612,6 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Varoitus: Olemme ristiriidassa vertaisten kanssa! Sinun tulee päivittää tai toisten solmujen tulee päivitää.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d viimeisestä 100 lohkosta sisälsi odottamattoman versiotiedon</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s vioittunut, korjaaminen epäonnistui</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool on oltava vähintään %d MB</translation> </message> @@ -3255,6 +3620,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>-%s -osoitteen '%s' selvittäminen epäonnistui</translation> </message> <message> + <source>Change index out of range</source> + <translation>Vaihda hakemisto alueen ulkopuolelle</translation> + </message> + <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Konfigurointiasetuksen %s käyttöön vain %s -verkossa, kun osassa [%s].</translation> + </message> + <message> <source>Copyright (C) %i-%i</source> <translation>Tekijänoikeus (C) %i-%i</translation> </message> @@ -3263,6 +3636,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Vioittunut lohkotietokanta havaittu</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>Asmap-tiedostoa %s ei löytynyt</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Asmap-tiedostoa %s ei voitu jäsentää</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Haluatko uudelleenrakentaa lohkotietokannan nyt?</translation> </message> @@ -3279,6 +3660,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Virhe ladattaessa %s</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation>Virhe %s:n lataamisessa: Yksityiset avaimet voidaan poistaa käytöstä vain luomisen aikana</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>Virhe ladattaessa %s: Lompakko vioittunut</translation> </message> @@ -3303,6 +3688,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Lompakkoa ei voitu tarkastaa alustuksen yhteydessä.</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Tietokannan todennus epäonnistui</translation> + </message> + <message> <source>Importing...</source> <translation>Tuodaan...</translation> </message> @@ -3327,10 +3716,42 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Virheellinen määrä -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase: Lausekkeen suorittaminen tietokannan %s todentamista varten epäonnistui</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: sqlite-lompakkokaavioversion %s nouto epäonnistui</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation>SQLiteDatabase: Sovellustunnisteen %s nouto epäonnistui</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase: Lausekkeen valmistelu tietokannan %s todentamista varten epäonnistui</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase: Tietokantatodennusvirheen %s luku epäonnistui</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase: Odottamaton sovellustunniste. %u odotettu, %u saatu</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>Unknown address type '%s'</source> + <translation>Tuntematon osoitetyyppi '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Tuntematon vaihtorahatyyppi '%s'</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Päivitetään txindex -tietokantaa</translation> </message> @@ -3339,10 +3760,6 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Ladataan P2P-vertaisten osoitteita...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Virhe: Liian vähän levytilaa!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Ladataan kieltolistaa...</translation> </message> @@ -3407,14 +3824,50 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Virhe: Saapuvien yhteyksien kuuntelu epäonnistui (kuuntelu palautti virheen %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s on vioittunut. Yritä käyttää lompakkotyökalua bitcoin-wallet pelastaaksesi sen tai palauttaa varmuuskopio.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Muuta kuin HD-jaettua lompakkoa ei voi päivittää ilman päivitystä tukemaan esijaettua avainvarastoa. Käytä versiota 169900 tai älä kaytä määritettyä versiota.</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>Virheellinen summa -maxtxfee =: '%s' (täytyy olla vähintään %s minrelay-kulu, jotta estetään jumiutuneet siirtotapahtumat)</translation> + </message> + <message> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation>Siirtomäärä on liian pieni lähetettäväksi kulun vähentämisen jälkeen.</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Tämä virhe voi tapahtua, jos tämä lompakko ei sammutettu siististi ja ladattiin viimeksi uudempaa Berkeley DB -versiota käyttäneellä ohjelmalla. Tässä tapauksessa käytä sitä ohjelmaa, joka viimeksi latasi tämän lompakon.</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Tämä on maksimimäärä, jonka maksat siirtokuluina (normaalien kulujen lisäksi) pistääksesi osittaiskulutuksen välttämisen tavallisen kolikonvalinnan edelle.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Siirtoon tarvitaan vaihto-osoite, muttemme voi luoda sitä. Ole hyvä ja kutsu ensin keypoolrefill.</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>Palataksesi karsimattomaan tilaan joudut uudelleenrakentamaan tietokannan -reindex -valinnalla. Tämä lataa koko lohkoketjun uudestaan.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Kriittinen sisäinen virhe kohdattiin, katso debug.log lisätietoja varten</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>-peerblockfiltersiä ei voida asettaa ilman -blockfilterindexiä.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Liian vähän levytilaa!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Virheitä tietokantaa luettaessa, ohjelma pysäytetään.</translation> </message> @@ -3427,6 +3880,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Virhe: levytila vähissä kohteessa %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Virhe: Avainallas tyhjentyi, ole hyvä ja kutsu keypoolrefill ensin</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Kulutaso (%s) on alempi, kuin minimikulutasoasetus (%s)</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Virheellinen -onion osoite tai isäntänimi: '%s'</translation> </message> @@ -3447,6 +3908,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Pitää määritellä portti argumentilla -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Välityspalvelinta ei ole määritetty. Käytä -proxy=<ip> tai -proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Karsintatila ei ole yhteensopiva -blockfilterindex valinnan kanssa</translation> </message> @@ -3501,6 +3966,14 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>PID-tiedostoa '%s' ei voitu luoda: %s</translation> </message> <message> + <source>Unable to generate initial keys</source> + <translation>Alkuavaimia ei voi luoda</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Tuntematon -lohkosuodatusindeksiarvo %s.</translation> + </message> + <message> <source>Verifying wallet(s)...</source> <translation>Varmistetaan lompakko(ja)...</translation> </message> @@ -3509,10 +3982,6 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Varoitus: tuntemattomia uusia sääntöjä aktivoitu (versiobitti %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Tyhjennetään kaikki rahansiirrot lompakosta....</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee on asetettu erittäin suureksi! Tämänkokoisia kuluja saatetaan maksaa yhdessä rahansiirrossa.</translation> </message> @@ -3525,10 +3994,6 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Verkon versiokenttä (%i) ylittää sallitun pituuden (%i). Vähennä uacomments:in arvoa tai kokoa.</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>Varoitus: Lompakkotiedosto on vioittunut, tiedot on korjattu. Alkuperäinen %s talletettu nimellä %s kohteeseen %s; mikäli taseesi tai siirtotapahtumat ovat virheellisiä, on suositeltavaa palauttaa lompakko varmuuskopioista.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s on asetettu todella korkeaksi!</translation> </message> @@ -3550,7 +4015,7 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t </message> <message> <source>This is the transaction fee you will pay if you send a transaction.</source> - <translation>Tämä on lähetyksestä maksettava maksu jonka maksat</translation> + <translation>Tämä on se siirtomaksu, jonka maksat, mikäli lähetät siirron.</translation> </message> <message> <source>Transaction amounts must not be negative</source> @@ -3577,6 +4042,10 @@ Huom: Koska siirtomaksu lasketaan tavujen mukaan, niin määrittelemällä 500 t <translation>Siirtomaksun arviointi epäonnistui. Odota muutama lohko tai käytä -fallbackfee -valintaa..</translation> </message> <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Varoitus: lompakosta {%s} tunnistetut yksityiset avaimet, on poistettu käytöstä</translation> + </message> + <message> <source>Cannot write to data directory '%s'; check permissions.</source> <translation>Hakemistoon '%s' ei voida kirjoittaa. Tarkista käyttöoikeudet.</translation> </message> diff --git a/src/qt/locale/bitcoin_fil.ts b/src/qt/locale/bitcoin_fil.ts index f7b8000439..1051db437b 100644 --- a/src/qt/locale/bitcoin_fil.ts +++ b/src/qt/locale/bitcoin_fil.ts @@ -132,6 +132,10 @@ <translation>Ulitin ang bagong passphrase</translation> </message> <message> + <source>Show passphrase</source> + <translation>Ipakita ang Passphrase</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>I-encrypt ang walet.</translation> </message> @@ -172,6 +176,30 @@ <translation>Naka-encrypt ang walet.</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Ipasok ang bagong passphrase para sa wallet. (1)Mangyaring gumamit ng isang passphrase na(2) sampu o higit pang mga random na character(2), o (3)walo o higit pang mga salita(3).</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Ipasok ang lumang passphrase at bagong passphrase para sa pitaka.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Tandaan na ang pag-encrypt ng iyong pitaka ay hindi maaaring ganap na maprotektahan ang iyong mga bitcoin mula sa pagnanakaw ng malware na nahahawa sa iyong computer.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Ang naka-encrypt na wallet</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Malapit na ma-encrypt ang iyong pitaka.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Ang iyong wallet ay naka-encrypt na ngayon.</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>MAHALAGA: Anumang nakaraang mga backup na ginawa mo sa iyong walet file ay dapat mapalitan ng bagong-buong, naka-encrypt na walet file. Para sa mga kadahilanang pangseguridad, ang mga nakaraang pag-backup ng hindi naka-encrypt na walet file ay mapagwawalang-silbi sa sandaling simulan mong gamitin ang bagong naka-encrypt na walet.</translation> </message> @@ -294,6 +322,14 @@ <translation>Buksan ang URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Gumawa ng Pitaka</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Gumawa ng Bagong Pitaka</translation> + </message> + <message> <source>Wallet:</source> <translation>Walet:</translation> </message> @@ -434,6 +470,10 @@ <translation>Napapanahon</translation> </message> <message> + <source>Node window</source> + <translation>Bintana ng Node</translation> + </message> + <message> <source>&Sending addresses</source> <translation>Mga address para sa pagpapadala</translation> </message> @@ -565,11 +605,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Walet ay na-encrypt at kasalukuyang naka-lock.</translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>May nangyaring malubhang kamalian. Hindi na kayang magpatuloy ng ligtas ang Bitcoin at ito ay hihinto na.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -723,10 +759,38 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Create wallet failed</source> + <translation>Nabigo ang Pag likha ng Pitaka</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Gumawa ng Babala ng Pitaka</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Gumawa ng Pitaka</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Pangalan ng Pitaka</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Huwag paganahin ang Privbadong susi</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Gumawa ng Blankong Pitaka</translation> + </message> + <message> + <source>Create</source> + <translation>Gumawa</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -934,6 +998,10 @@ <translation>Itago</translation> </message> <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Hindi alam. S-in-i-sync ang mga Header (%1, %2%)...</translation> </message> @@ -948,6 +1016,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Nabigo ang bukas na pitaka</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Buksan ang babala sa pitaka</translation> + </message> + <message> <source>default wallet</source> <translation>walet na default</translation> </message> @@ -991,10 +1067,6 @@ <translation>Pinapakita kung ang ibinibigay na default SOCKS5 proxy ay ginagamit upang maabot ang mga peers sa pamamagitan nitong uri ng network.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Gumamit ng hiwalay na SOCKS&5 proxy upang maabot ang mga peers sa pamamagitan ng mga tagong serbisyo ng Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Itago ang icon mula sa trey ng sistema.</translation> </message> @@ -1123,10 +1195,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Kumunekta sa Bitcoin network sa pamamagitan ng hiwalay na SOCKS5 proxy para sa mga tagong serbisyo ng Tor.</translation> - </message> - <message> <source>&Window</source> <translation>Window</translation> </message> @@ -1301,7 +1369,18 @@ <source>Current total balance in watch-only addresses</source> <translation>Kasalukuyang kabuuan ng balanse sa mga watch-only address</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Kabuuang Halaga</translation> + </message> + <message> + <source>or</source> + <translation>o</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1482,6 +1561,10 @@ <translation>Kamalian sa pag-e-encode ng URI sa QR Code.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>Hindi magagamit ang suporta ng QR code.</translation> + </message> + <message> <source>Save QR Code</source> <translation>I-save ang QR Code</translation> </message> @@ -1549,10 +1632,6 @@ <translation>Block chain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Kasalukuyang dami ng blocks</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memory Pool</translation> </message> @@ -1597,10 +1676,6 @@ <translation>Pumili ng peer upang tingnan ang detalyadong impormasyon.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Whitelisted</translation> - </message> - <message> <source>Direction</source> <translation>Direksyon</translation> </message> @@ -1621,10 +1696,23 @@ <translation>Mga block na na-sync</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Ginamit ang na-map na Autonomous System para sa pag-iba-iba ng pagpipilian ng kapwa.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapa sa AS +</translation> + </message> + <message> <source>User Agent</source> <translation>Ahente ng User</translation> </message> <message> + <source>Node window</source> + <translation>Bintana ng Node</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>Buksan ang %1 debug log file mula sa kasalukuyang directoryo ng datos. Maaari itong tumagal ng ilang segundo para sa mga malalaking log file.</translation> </message> @@ -1641,10 +1729,6 @@ <translation>Mga serbisyo</translation> </message> <message> - <source>Ban Score</source> - <translation>Ban Score</translation> - </message> - <message> <source>Connection Time</source> <translation>Oras ng Koneksyon</translation> </message> @@ -1793,14 +1877,6 @@ <translation>Papalabas</translation> </message> <message> - <source>Yes</source> - <translation>Oo</translation> - </message> - <message> - <source>No</source> - <translation>Hindi</translation> - </message> - <message> <source>Unknown</source> <translation>Hindi alam</translation> </message> @@ -1836,6 +1912,18 @@ <translation>Opsyonal na halaga upang humiling. Iwanan itong walang laman o zero upang hindi humiling ng tiyak na halaga.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Isang opsyonal na label upang maiugnay sa bagong address ng pagtanggap (ginamit mo upang makilala ang isang invoice). Nakalakip din ito sa kahilingan sa pagbabayad.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Isang opsyonal na mensahe na naka-attach sa kahilingan sa pagbabayad at maaaring ipakita sa nagpadala.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>& Lumikha ng bagong address sa pagtanggap</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>Burahin ang laman ng lahat ng patlang ng form.</translation> </message> @@ -1887,12 +1975,24 @@ <source>Copy amount</source> <translation>Kopyahin ang halaga</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Hindi magawang ma-unlock ang walet.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Code</translation> + <source>Amount:</source> + <translation>Halaga:</translation> + </message> + <message> + <source>Message:</source> + <translation>Mensahe:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Walet:</translation> </message> <message> <source>Copy &URI</source> @@ -1914,30 +2014,6 @@ <source>Payment information</source> <translation>Impormasyon sa pagbabayad</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Address</translation> - </message> - <message> - <source>Amount</source> - <translation>Halaga</translation> - </message> - <message> - <source>Label</source> - <translation>Label</translation> - </message> - <message> - <source>Message</source> - <translation>Mensahe</translation> - </message> - <message> - <source>Wallet</source> - <translation>Walet</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2085,6 +2161,10 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Dust:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Itago ang mga Setting ng bayad sa Transaksyon</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Kapag mas kaunti ang dami ng transaksyon kaysa sa puwang sa mga blocks, ang mga minero pati na rin ang mga relaying node ay maaaring magpatupad ng minimum na bayad. Ang pagbabayad lamang ng minimum na bayad na ito ay maayos, ngunit malaman na maaari itong magresulta sa hindi kailanmang nagkukumpirmang transaksyon sa sandaling magkaroon ng higit na pangangailangan para sa mga transaksyon ng bitcoin kaysa sa kayang i-proseso ng network.</translation> </message> @@ -2153,10 +2233,18 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>%1 (%2 mga block)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Lumikha ng Unsigned</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 sa %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Nais mo bang i-draft ang transaksyong ito?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Sigurado ka bang nais mong magpadala?</translation> </message> @@ -2185,10 +2273,26 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Kabuuang Halaga</translation> </message> <message> + <source>To review recipient list click "Show Details..."</source> + <translation>Upang suriin ang listahan ng tatanggap i-click ang "Ipakita ang Mga Detalye ..."</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Kumpirmahin magpadala ng coins</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Kumpirmahin ang panukala sa transaksyon</translation> + </message> + <message> + <source>Send</source> + <translation>Ipadala</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Balanse lamang sa panonood:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Ang address ng tatanggap ay hindi wasto. Mangyaring suriin muli.</translation> </message> @@ -2442,6 +2546,10 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Kinansela ang pag-unlock ng walet.</translation> </message> <message> + <source>No error</source> + <translation>Walang Kamalian</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Hindi magagamit ang private key para sa pinasok na address.</translation> </message> @@ -2942,12 +3050,12 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Ang pagsasara ng walet nang masyadong matagal ay maaaring magresulta sa pangangailangan ng pag-resync sa buong chain kung pinagana ang pruning.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Walang walet ang na-load.</translation> + <source>Create a new wallet</source> + <translation>Gumawa ng Bagong Pitaka</translation> </message> </context> <context> @@ -2985,6 +3093,14 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Kumpirmahin ang fee bump</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>Hindi ma-draft ang transaksyon</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>Kinopya ang PSBT</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Hindi mapirmahan ang transaksyon.</translation> </message> @@ -3008,6 +3124,10 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Angkatin ang datos sa kasalukuyang tab sa talaksan</translation> </message> <message> + <source>Error</source> + <translation>Kamalian</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Backup na walet</translation> </message> @@ -3051,10 +3171,6 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Prune: ang huling pag-synchronize ng walet ay lampas sa pruned data. Kailangan mong mag-reindex (i-download muli ang buong blockchain sa kaso ng pruned node)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Kamalian: May naganap na isang nakamamatay na panloob na error, tingnan ang debug.log para sa detalye</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Pruning blockstore...</translation> </message> @@ -3067,10 +3183,6 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Ang mga %s developers</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Hindi makagawa ng change-address key. Walang mga key sa panloob na keypool at hindi makagawa ng anumang mga key.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Hindi makakuha ng lock sa direktoryo ng data %s. Malamang na tumatakbo ang %s.</translation> </message> @@ -3115,14 +3227,6 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Babala: Mukhang hindi kami ganap na sumasang-ayon sa aming mga peers! Maaaring kailanganin mong mag-upgrade, o ang ibang mga node ay maaaring kailanganing mag-upgrade.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d ng huling 100 na mga block ay may hindi inaasahang bersyon</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s tiwali, nabigo ang pag-salvage</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>ang -maxmempool ay dapat hindi bababa sa %d MB</translation> </message> @@ -3397,10 +3501,6 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Babala: na-activate ang mga hindi kilalang bagong patakaran (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Z-in-a-zap ang lahat ng mga transaksyon mula sa walet...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee ay nakatakda nang napakataas! Ang mga bayad na ganito kalaki ay maaaring bayaran sa isang solong transaksyon.</translation> </message> @@ -3413,10 +3513,6 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Ang kabuuang haba ng string ng bersyon ng network (%i) ay lumampas sa maximum na haba (%i). Bawasan ang bilang o laki ng mga uacomment.</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>Babala: Ang file ng walet ay tiwali, ang data ay nailigtas! Nai-save ang original na %s bilang %s sa %s; kung ang iyong balanse o mga transaksyon ay hindi tama dapat mong ibalik mula sa backup.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>Ang %s ay nakatakda ng napakataas!</translation> </message> @@ -3461,10 +3557,6 @@ Tandaan: Dahil ang bayad ay kinakalkula sa bawat-byte na batayan, ang bayad ng <translation>Hindi sapat na pondo</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>Hindi ma-upgrade ang non HD split wallet kung hindi mag-u-upgrade upang suportahan ang pre split keypool. Mangyaring gamitin ang -upgradewallet=169900 o -upgradewallet na walang tinukoy na bersyon.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Nabigo ang pagtatantya ng bayad. Hindi pinagana ang Fallbackfee. Maghintay ng ilang mga block o paganahin -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 1cddb413ef..aa30c6a0e7 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Copier l’adresse sélectionnée actuellement dans le presse-papiers</translation> + <translation>Copier dans le presse-papiers l’adresse sélectionnée actuellement</translation> </message> <message> <source>&Copy</source> @@ -31,7 +31,7 @@ </message> <message> <source>Enter address or label to search</source> - <translation>Saisir une adresse ou une étiquette à rechercher</translation> + <translation>Saisissez une adresse ou une étiquette à rechercher</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -67,11 +67,13 @@ </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> - <translation>Ce sont vos adresses Bitcoin pour envoyer des paiements. Vérifiez toujours le montant et l’adresse du destinataire avant d’envoyer des pièces.</translation> + <translation>Ce sont vos adresses Bitcoin pour envoyer des paiements. Vérifiez toujours le montant et l’adresse du destinataire avant d’envoyer des pièces.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Ce sont vos adresses Bitcoin pour recevoir des paiements. Utilisez le bouton 'Créer une nouvelle adresse de réception' dans l’onglet Recevoir afin de créer de nouvelles adresses.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Ce sont vos adresses Bitcoin pour recevoir des paiements. Utilisez le bouton « Créer une nouvelle adresse de réception » dans l’onglet Recevoir afin de créer de nouvelles adresses. +Il n’est possible de signer qu’avec les adresses de type « legacy ».</translation> </message> <message> <source>&Copy Address</source> @@ -125,7 +127,7 @@ </message> <message> <source>Enter passphrase</source> - <translation>Saisir la phrase de passe</translation> + <translation>Saisissez la phrase de passe</translation> </message> <message> <source>New passphrase</source> @@ -185,7 +187,7 @@ </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation>Saisir l’ancienne puis la nouvelle phrase de passe du porte-monnaie.</translation> + <translation>Saisissez l’ancienne puis la nouvelle phrase de passe du porte-monnaie.</translation> </message> <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> @@ -237,7 +239,7 @@ </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation>Avertissement : La touche Verr. Maj. est activée !</translation> + <translation>Avertissement : La touche Verr. Maj. est activée</translation> </message> </context> <context> @@ -291,7 +293,7 @@ </message> <message> <source>Show information about %1</source> - <translation>Afficher des informations à propos de %1</translation> + <translation>Afficher des renseignements à propos de %1</translation> </message> <message> <source>About &Qt</source> @@ -299,7 +301,7 @@ </message> <message> <source>Show information about Qt</source> - <translation>Afficher des informations sur Qt</translation> + <translation>Afficher des renseignements sur Qt</translation> </message> <message> <source>&Options...</source> @@ -339,7 +341,7 @@ </message> <message> <source>Click to disable network activity.</source> - <translation>Cliquer pour désactiver l’activité réseau.</translation> + <translation>Cliquez pour désactiver l’activité réseau.</translation> </message> <message> <source>Network activity disabled.</source> @@ -347,7 +349,7 @@ </message> <message> <source>Click to enable network activity again.</source> - <translation>Cliquer pour réactiver l’activité réseau.</translation> + <translation>Cliquez pour réactiver l’activité réseau.</translation> </message> <message> <source>Syncing Headers (%1%)...</source> @@ -363,7 +365,7 @@ </message> <message> <source>Send coins to a Bitcoin address</source> - <translation>Envoyer des pièces à une adresse Bitcoin</translation> + <translation>Envoyer des pièces à une adresse Bitcoin</translation> </message> <message> <source>Backup wallet to another location</source> @@ -399,11 +401,11 @@ </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>Signer les messages avec vos adresses Bitcoin pour prouver que vous les détenez</translation> + <translation>Signer les messages avec vos adresses Bitcoin pour prouver que vous les détenez</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>Vérifier les messages pour s’assurer qu’ils ont été signés avec les adresses Bitcoin indiquées</translation> + <translation>Vérifier les messages pour s’assurer qu’ils ont été signés avec les adresses Bitcoin indiquées</translation> </message> <message> <source>&File</source> @@ -439,7 +441,7 @@ </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network</source> - <translation><numerusform>%n connexion active avec le réseau Bitcoin</numerusform><numerusform>%n connexions actives avec le réseau Bitcoin</numerusform></translation> + <translation><numerusform>%n connexion active avec le réseau Bitcoin</numerusform><numerusform>%n connexions actives avec le réseau Bitcoin</numerusform></translation> </message> <message> <source>Indexing blocks on disk...</source> @@ -475,19 +477,35 @@ </message> <message> <source>Information</source> - <translation>Informations</translation> + <translation>Renseignements</translation> </message> <message> <source>Up to date</source> <translation>À jour</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Charger une TBSP d’un fichier…</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Charger une transaction Bitcoin signée partiellement</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Charger une TBSP du presse-papiers…</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Charger du presse-papiers une transaction Bitcoin signée partiellement</translation> + </message> + <message> <source>Node window</source> <translation>Fenêtre des nœuds</translation> </message> <message> <source>Open node debugging and diagnostic console</source> - <translation>Ouvrir une console de débogage de noeuds et de diagnostic</translation> + <translation>Ouvrir une console de débogage de nœuds et de diagnostic</translation> </message> <message> <source>&Sending addresses</source> @@ -503,7 +521,7 @@ </message> <message> <source>Open Wallet</source> - <translation>Ouvrir le porte-monnaie</translation> + <translation>Ouvrir un porte-monnaie</translation> </message> <message> <source>Open a wallet</source> @@ -518,10 +536,26 @@ <translation>Fermer le porte-monnaie</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Fermer tous les porte-monnaie…</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Fermer tous les porte-monnaie</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Afficher le message d’aide de %1 pour obtenir la liste des options de ligne de commande Bitcoin possibles.</translation> </message> <message> + <source>&Mask values</source> + <translation>&Dissimuler les montants</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Dissimuler les montants dans l’onglet Vue d’ensemble</translation> + </message> + <message> <source>default wallet</source> <translation>porte-monnaie par défaut</translation> </message> @@ -586,7 +620,7 @@ <message> <source>Type: %1 </source> - <translation>Type : %1 + <translation>Type : %1 </translation> </message> <message> @@ -630,8 +664,12 @@ <translation>Le porte-monnaie est <b>chiffré</b> et actuellement <b>verrouillé</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Une erreur fatale est survenue. Bitcoin ne peut plus continuer en toute sécurité et va s’arrêter.</translation> + <source>Original message:</source> + <translation>Message original :</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Une erreur fatale est survenue. %1 ne peut plus continuer de façon sûre et va s’arrêter.</translation> </message> </context> <context> @@ -835,6 +873,14 @@ <translation>Créer un porte-monnaie vide</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Utiliser des descripteurs pour la gestion des scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Porte-monnaie de descripteurs</translation> + </message> + <message> <source>Create</source> <translation>Créer</translation> </message> @@ -875,7 +921,7 @@ </message> <message> <source>The entered address "%1" is not a valid Bitcoin address.</source> - <translation>L’adresse saisie « %1 » n’est pas une adresse Bitcoin valide.</translation> + <translation>L’adresse saisie « %1 » n’est pas une adresse Bitcoin valide.</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> @@ -944,7 +990,7 @@ </message> <message> <source>As this is the first time the program is launched, you can choose where %1 will store its data.</source> - <translation>Puisque c’est la première fois que le logiciel est lancé, vous pouvez choisir où %1 stockera ses données.</translation> + <translation>Comme le logiciel est lancé pour la première fois, vous pouvez choisir où %1 stockera ses données.</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> @@ -988,7 +1034,7 @@ </message> <message> <source>%1 will download and store a copy of the Bitcoin block chain.</source> - <translation>%1 téléchargera et stockera une copie de la chaîne de blocs Bitcoin.</translation> + <translation>%1 téléchargera et stockera une copie de la chaîne de blocs Bitcoin.</translation> </message> <message> <source>The wallet will also be stored in this directory.</source> @@ -1023,7 +1069,7 @@ </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>Les transactions récentes ne sont peut-être pas encore visibles et par conséquent le solde de votre porte-monnaie est peut-être erroné. Ces informations seront justes quand votre porte-monnaie aura fini de se synchroniser avec le réseau Bitcoin, comme décrit ci-dessous.</translation> + <translation>Les transactions récentes ne sont peut-être pas encore visibles et par conséquent le solde de votre porte-monnaie est peut-être erroné. Ces renseignements seront justes quand votre porte-monnaie aura fini de se synchroniser avec le réseau Bitcoin, comme décrit ci-dessous.</translation> </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> @@ -1132,17 +1178,13 @@ </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> - <translation>Adresse IP du mandataire (p. ex. IPv4 : 127.0.0.1 / IPv6 : ::1)</translation> + <translation>Adresse IP du mandataire (p. ex. 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>Indique si le mandataire SOCKS5 par défaut fourni est utilisé pour atteindre des pairs par ce type de réseau.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Utiliser un mandataire SOCKS&5 séparé pour atteindre les pairs en utilisant les services cachés de Tor.</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Cacher l’icône dans la zone de notification.</translation> </message> @@ -1224,7 +1266,7 @@ </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>Ouvrir automatiquement le port du client Bitcoin sur le routeur. Cela ne fonctionne que si votre routeur prend en charge l’UPnP et si la fonction est activée.</translation> + <translation>Ouvrir automatiquement le port du client Bitcoin sur le routeur. Cela ne fonctionne que si votre routeur prend en charge l’UPnP et si la fonction est activée.</translation> </message> <message> <source>Map port using &UPnP</source> @@ -1240,7 +1282,7 @@ </message> <message> <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> - <translation>Se connecter au réseau Bitcoin par un mandataire SOCKS5.</translation> + <translation>Se connecter au réseau Bitcoin par un mandataire SOCKS5.</translation> </message> <message> <source>&Connect through SOCKS5 proxy (default proxy):</source> @@ -1275,10 +1317,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Se connecter au réseau Bitcoin au travers d’un mandataire SOCKS5 séparé pour les services cachés de Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Fenêtre</translation> </message> @@ -1319,6 +1357,14 @@ <translation>Afficher ou non les fonctions de contrôle des pièces.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Se connecter au réseau Bitcoin par un mandataire SOCKS5 séparé pour les services onion de Tor.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Utiliser un mandataire SOCKS5 séparé pour atteindre les pairs par les services onion de Tor.</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>URL de transaction &tierces</translation> </message> @@ -1348,7 +1394,7 @@ </message> <message> <source>Client restart required to activate changes.</source> - <translation>Le redémarrage du client est exigé pour activer les changements.</translation> + <translation>Le client doit être redémarrer pour activer les changements.</translation> </message> <message> <source>Client will be shut down. Do you want to proceed?</source> @@ -1387,7 +1433,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 se synchronise automatiquement avec le réseau Bitcoin dès qu’une connexion est établie, mais ce processus n’est pas encore achevé.</translation> + <translation>Les renseignements affichés 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> @@ -1453,6 +1499,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Solde total actuel dans des adresses juste-regarder</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Le mode privé est activé dans l’onglet Vue d’ensemble. Pour afficher les montants, décocher Paramètres -> Dissimuler les montants.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Fenêtre de dialogue</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Signer la transaction</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Diffuser la transaction</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Copier dans le presse-papiers</translation> + </message> + <message> + <source>Save...</source> + <translation>Enregistrer…</translation> + </message> + <message> + <source>Close</source> + <translation>Fermer</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Échec de chargement de la transaction : %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Échec de signature de la transaction : %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Aucune autre entrée n’a pu être signée.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>%1 entrées ont été signées, mais il faut encore d’autres signatures.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>La transaction a été signée avec succès et est prête à être diffusée.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Erreur inconnue lors de traitement de la transaction.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>La transaction a été diffusée avec succès. ID de la transaction : %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Échec de diffusion de la transaction : %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>La TBSP a été copiée dans le presse-papiers.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Enregistrer les données de la transaction</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transaction signée partiellement (fichier binaire) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>La TBSP a été enregistrée sur le disque.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation> * envoie %1 à %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Impossible de calculer les frais de la transaction ou le montant total de la transaction.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Paye des frais de transaction de :</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Montant total</translation> + </message> + <message> + <source>or</source> + <translation>ou</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>La transaction a %1 entrées non signées.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Il manque des renseignements sur les entrées dans la transaction.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>La transaction a encore besoin d’une ou de signatures.</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Mais ce porte-monnaie ne peut pas signer de transactions.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Mais ce porte-monnaie n’a pas les bonnes clés.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>La transaction est complètement signée et prête à être diffusée.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>L’état de la transaction est inconnu.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1486,11 +1659,11 @@ </message> <message> <source>Invalid payment address %1</source> - <translation>Adresse de paiement invalide %1</translation> + <translation>L’adresse de paiement est invalide %1</translation> </message> <message> <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> - <translation>L’URI ne peut pas être analysée ! Cela peut être causé par une adresse Bitcoin invalide ou par des paramètres d’URI mal formés.</translation> + <translation>L’URI ne peut pas être analysée. Cela peut être causé par une adresse Bitcoin invalide ou par des paramètres d’URI mal formés.</translation> </message> <message> <source>Payment request file handling</source> @@ -1532,7 +1705,7 @@ </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> - <translation>Saisir une adresse Bitcoin (p. ex. %1)</translation> + <translation>Saisissez une adresse Bitcoin (p. ex. %1)</translation> </message> <message> <source>%1 d</source> @@ -1619,6 +1792,10 @@ <translation>Erreur : %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Erreur d’initialisation des paramètres : %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 ne s’est pas encore arrêté en toute sécurité…</translation> </message> @@ -1670,7 +1847,7 @@ </message> <message> <source>&Information</source> - <translation>&Informations</translation> + <translation>&Renseignements</translation> </message> <message> <source>General</source> @@ -1717,10 +1894,6 @@ <translation>Chaîne de blocs</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Nombre actuel de blocs</translation> - </message> - <message> <source>Memory Pool</source> <translation>Réserve de mémoire</translation> </message> @@ -1762,11 +1935,7 @@ </message> <message> <source>Select a peer to view detailed information.</source> - <translation>Choisir un pair pour voir des informations détaillées.</translation> - </message> - <message> - <source>Whitelisted</source> - <translation>Dans la liste blanche</translation> + <translation>Sélectionnez un pair pour afficher des renseignements détaillés.</translation> </message> <message> <source>Direction</source> @@ -1789,6 +1958,14 @@ <translation>Blocs synchronisés</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Le système autonome mappé utilisé pour diversifier la sélection des pairs.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>SA mappé</translation> + </message> + <message> <source>User Agent</source> <translation>Agent utilisateur</translation> </message> @@ -1797,6 +1974,10 @@ <translation>Fenêtre des nœuds</translation> </message> <message> + <source>Current block height</source> + <translation>Hauteur du bloc courant</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>Ouvrir le fichier journal de débogage de %1 à partir du répertoire de données actuel. Cela peut prendre quelques secondes pour les fichiers journaux de grande taille.</translation> </message> @@ -1809,12 +1990,12 @@ <translation>Augmenter la taille de police</translation> </message> <message> - <source>Services</source> - <translation>Services</translation> + <source>Permissions</source> + <translation>Autorisations</translation> </message> <message> - <source>Ban Score</source> - <translation>Pointage des bannissements</translation> + <source>Services</source> + <translation>Services</translation> </message> <message> <source>Connection Time</source> @@ -1870,11 +2051,11 @@ </message> <message> <source>In:</source> - <translation>Entrant :</translation> + <translation>Entrant :</translation> </message> <message> <source>Out:</source> - <translation>Sortant :</translation> + <translation>Sortant :</translation> </message> <message> <source>Debug log file</source> @@ -1946,7 +2127,7 @@ </message> <message> <source>(node id: %1)</source> - <translation>(ID de nœud : %1)</translation> + <translation>(ID de nœud : %1)</translation> </message> <message> <source>via %1</source> @@ -1965,14 +2146,6 @@ <translation>Sortant</translation> </message> <message> - <source>Yes</source> - <translation>Oui</translation> - </message> - <message> - <source>No</source> - <translation>Non</translation> - </message> - <message> <source>Unknown</source> <translation>Inconnu</translation> </message> @@ -1981,7 +2154,7 @@ <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation>&Montant :</translation> + <translation>&Montant :</translation> </message> <message> <source>&Label:</source> @@ -1989,11 +2162,11 @@ </message> <message> <source>&Message:</source> - <translation>M&essage :</translation> + <translation>M&essage :</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>Un message facultatif à joindre à la demande de paiement et qui sera affiché à l’ouverture de celle-ci. Note : Le message ne sera pas envoyé avec le paiement par le réseau Bitcoin.</translation> + <translation>Un message facultatif à joindre à la demande de paiement et qui sera affiché à l’ouverture de celle-ci. Note : Le message ne sera pas envoyé avec le paiement par le réseau Bitcoin.</translation> </message> <message> <source>An optional label to associate with the new receiving address.</source> @@ -2005,7 +2178,7 @@ </message> <message> <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> - <translation>Un montant facultatif à demander. Ne rien saisir ou un zéro pour ne pas demander de montant précis.</translation> + <translation>Un montant facultatif à demander. Ne saisissez rien ou un zéro pour ne pas demander de montant précis.</translation> </message> <message> <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> @@ -2049,11 +2222,11 @@ </message> <message> <source>Remove the selected entries from the list</source> - <translation>Retirer les entrées sélectionnées de la liste</translation> + <translation>Supprimer les entrées sélectionnées de la liste</translation> </message> <message> <source>Remove</source> - <translation>Retirer</translation> + <translation>Supprimer</translation> </message> <message> <source>Copy URI</source> @@ -2071,56 +2244,60 @@ <source>Copy amount</source> <translation>Copier le montant</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Impossible de déverrouiller le porte-monnaie.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Impossible de générer la nouvelle adresse %1</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Code QR</translation> - </message> - <message> - <source>Copy &URI</source> - <translation>Copier l’&URI</translation> + <source>Request payment to ...</source> + <translation>Demander un paiement à…</translation> </message> <message> - <source>Copy &Address</source> - <translation>Copier l’&adresse</translation> + <source>Address:</source> + <translation>Adresse :</translation> </message> <message> - <source>&Save Image...</source> - <translation>&Enregistrer l’image…</translation> + <source>Amount:</source> + <translation>Montant :</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Demande de paiement à %1</translation> + <source>Label:</source> + <translation>Étiquette :</translation> </message> <message> - <source>Payment information</source> - <translation>Informations de paiement</translation> + <source>Message:</source> + <translation>Message :</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Porte-monnaie :</translation> </message> <message> - <source>Address</source> - <translation>Adresse</translation> + <source>Copy &URI</source> + <translation>Copier l’&URI</translation> </message> <message> - <source>Amount</source> - <translation>Montant</translation> + <source>Copy &Address</source> + <translation>Copier l’&adresse</translation> </message> <message> - <source>Label</source> - <translation>Étiquette</translation> + <source>&Save Image...</source> + <translation>&Enregistrer l’image…</translation> </message> <message> - <source>Message</source> - <translation>Message</translation> + <source>Request payment to %1</source> + <translation>Demande de paiement à %1</translation> </message> <message> - <source>Wallet</source> - <translation>Porte-monnaie</translation> + <source>Payment information</source> + <translation>Renseignements de paiement</translation> </message> </context> <context> @@ -2174,15 +2351,15 @@ </message> <message> <source>Insufficient funds!</source> - <translation>Les fonds sont insuffisants !</translation> + <translation>Les fonds sont insuffisants</translation> </message> <message> <source>Quantity:</source> - <translation>Quantité :</translation> + <translation>Quantité :</translation> </message> <message> <source>Bytes:</source> - <translation>Octets :</translation> + <translation>Octets :</translation> </message> <message> <source>Amount:</source> @@ -2190,15 +2367,15 @@ </message> <message> <source>Fee:</source> - <translation>Frais :</translation> + <translation>Frais :</translation> </message> <message> <source>After Fee:</source> - <translation>Après les frais :</translation> + <translation>Après les frais :</translation> </message> <message> <source>Change:</source> - <translation>Monnaie :</translation> + <translation>Monnaie :</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> @@ -2210,7 +2387,7 @@ </message> <message> <source>Transaction Fee:</source> - <translation>Frais de transaction :</translation> + <translation>Frais de la transaction :</translation> </message> <message> <source>Choose...</source> @@ -2234,7 +2411,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>per kilobyte</source> - <translation>par kilo-octet</translation> + <translation>Par kilo-octet</translation> </message> <message> <source>Hide</source> @@ -2242,11 +2419,11 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Recommended:</source> - <translation>Recommandés :</translation> + <translation>Recommandés :</translation> </message> <message> <source>Custom:</source> - <translation>Personnalisés : </translation> + <translation>Personnalisés : </translation> </message> <message> <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> @@ -2266,7 +2443,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Dust:</source> - <translation>Poussière :</translation> + <translation>Poussière :</translation> </message> <message> <source>Hide transaction fee settings</source> @@ -2282,7 +2459,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Confirmation time target:</source> - <translation>Estimation du délai de confirmation :</translation> + <translation>Estimation du délai de confirmation :</translation> </message> <message> <source>Enable Replace-By-Fee</source> @@ -2290,7 +2467,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </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>Avec Remplacer-par-des-frais (BIP-125), vous pouvez augmenter les frais de transaction après qu’elle est envoyée. Sans cela, des frais plus élevés peuvent être recommandés pour compenser le risque accru de retard transactionnel.</translation> + <translation>Avec Remplacer-par-des-frais (BIP-125), vous pouvez augmenter les frais d’une transaction après qu’elle est envoyée. Sans cela, des frais plus élevés peuvent être recommandés pour compenser le risque accru de retard transactionnel.</translation> </message> <message> <source>Clear &All</source> @@ -2346,7 +2523,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Crée une transaction Bitcoin partiellement signée (TBPS) à utiliser, par exemple, avec un porte-monnaie %1 hors ligne ou avec un porte-monnaie matériel compatible TBPS.</translation> + <translation>Crée une transaction Bitcoin signée partiellement (TBSP) à utiliser, par exemple, avec un porte-monnaie %1 hors ligne ou avec un porte-monnaie matériel compatible TBSP.</translation> </message> <message> <source> from wallet '%1'</source> @@ -2362,15 +2539,27 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Do you want to draft this transaction?</source> - <translation>Souhaitez-vous créer une ébauche de cette transaction ?</translation> + <translation>Voulez-vous créer une ébauche de cette transaction ?</translation> </message> <message> <source>Are you sure you want to send?</source> <translation>Voulez-vous vraiment envoyer ?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Veuillez réviser votre proposition de transaction. Une transaction Bitcoin partiellement signée (TBPS) sera produite, que vous pourrez copier puis signer avec, par exemple, un porte-monnaie %1 hors ligne ou avec un porte-monnaie matériel compatible TBPS.</translation> + <source>Create Unsigned</source> + <translation>Créer une transaction non signée</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Enregistrer les données de la transaction</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transaction signée partiellement (fichier binaire) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>La TBSP a été enregistrée</translation> </message> <message> <source>or</source> @@ -2381,6 +2570,10 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Vous pouvez augmenter les frais ultérieurement (signale Remplacer-par-des-frais, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Veuillez réviser votre proposition de transaction. Une transaction Bitcoin partiellement signée (TBSP) sera produite, que vous pourrez enregistrer ou copier puis signer avec, par exemple, un porte-monnaie %1 hors ligne ou avec un porte-monnaie matériel compatible TBSP.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Veuillez vérifier votre transaction.</translation> </message> @@ -2409,18 +2602,10 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Confirmer la proposition de transaction</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Copier la TBPS dans le presse-papiers</translation> - </message> - <message> <source>Send</source> <translation>Envoyer</translation> </message> <message> - <source>PSBT copied</source> - <translation>La TBPS a été copiée</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Solde juste-regarder :</translation> </message> @@ -2442,11 +2627,11 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Duplicate address found: addresses should only be used once each.</source> - <translation>Adresse identique trouvée : chaque adresse ne devrait être utilisée qu’une fois.</translation> + <translation>Une adresse identique a été trouvée : chaque adresse ne devrait être utilisée qu’une fois.</translation> </message> <message> <source>Transaction creation failed!</source> - <translation>Échec de création de la transaction !</translation> + <translation>Échec de création de la transaction</translation> </message> <message> <source>A fee higher than %1 is considered an absurdly high fee.</source> @@ -2462,7 +2647,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Warning: Invalid Bitcoin address</source> - <translation>Avertissement : L’adresse Bitcoin est invalide</translation> + <translation>Avertissement : L’adresse Bitcoin est invalide</translation> </message> <message> <source>Warning: Unknown change address</source> @@ -2501,7 +2686,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>The Bitcoin address to send the payment to</source> - <translation>L’adresse Bitcoin à laquelle envoyer le paiement</translation> + <translation>L’adresse Bitcoin à laquelle envoyer le paiement</translation> </message> <message> <source>Alt+A</source> @@ -2517,7 +2702,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Remove this entry</source> - <translation>Retirer cette entrée</translation> + <translation>Supprimer cette entrée</translation> </message> <message> <source>The amount to send in the selected unit</source> @@ -2525,7 +2710,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </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>Les frais seront déduits du montant envoyé. Le destinataire recevra moins de bitcoins que le montant saisi dans le champ de montant. Si plusieurs destinataires sont sélectionnés, les frais seront partagés également..</translation> + <translation>Les frais seront déduits du montant envoyé. Le destinataire recevra moins de bitcoins que le montant saisi dans le champ de montant. Si plusieurs destinataires sont sélectionnés, les frais seront partagés également.</translation> </message> <message> <source>S&ubtract fee from amount</source> @@ -2549,19 +2734,19 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Enter a label for this address to add it to the list of used addresses</source> - <translation>Saisir une étiquette pour cette adresse afin de l’ajouter à la liste d’adresses utilisées</translation> + <translation>Saisissez une étiquette pour cette adresse afin de l’ajouter à la liste d’adresses utilisées</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>Un message qui était joint à l’URI bitcoin: et qui sera stocké avec la transaction pour référence. Note : Ce message ne sera pas envoyé par le réseau Bitcoin.</translation> + <translation>Un message qui était joint à l’URI bitcoin: et qui sera stocké avec la transaction pour référence. Note : Ce message ne sera pas envoyé par le réseau Bitcoin.</translation> </message> <message> <source>Pay To:</source> - <translation>Payer à :</translation> + <translation>Payer à :</translation> </message> <message> <source>Memo:</source> - <translation>Mémo :</translation> + <translation>Mémo :</translation> </message> </context> <context> @@ -2579,7 +2764,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <name>SignVerifyMessageDialog</name> <message> <source>Signatures - Sign / Verify a Message</source> - <translation>Signatures - Signer / vérifier un message</translation> + <translation>Signatures – Signer/vérifier un message</translation> </message> <message> <source>&Sign Message</source> @@ -2591,7 +2776,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>The Bitcoin address to sign the message with</source> - <translation>L’adresse Bitcoin avec laquelle signer le message</translation> + <translation>L’adresse Bitcoin avec laquelle signer le message</translation> </message> <message> <source>Choose previously used address</source> @@ -2611,7 +2796,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Enter the message you want to sign here</source> - <translation>Saisir ici le message que vous désirez signer</translation> + <translation>Saisissez ici le message que vous désirez signer</translation> </message> <message> <source>Signature</source> @@ -2623,7 +2808,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation>Signer le message afin de prouver que vous détenez cette adresse Bitcoin</translation> + <translation>Signer le message afin de prouver que vous détenez cette adresse Bitcoin</translation> </message> <message> <source>Sign &Message</source> @@ -2643,11 +2828,11 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </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>Saisir ci-dessous l’adresse du destinataire, le message (s’assurer de copier fidèlement les retours à la ligne, les espaces, les tabulations, etc.) et la signature pour vérifier le message. Faire attention à ne pas déduire davantage de la signature que ce qui est contenu dans le message signé même, pour éviter d’être trompé par une attaque d’homme du milieu. Prendre en compte que cela ne fait que prouver que le signataire reçoit l’adresse et ne peut pas prouver la provenance d’une transaction !</translation> + <translation>Saisissez ci-dessous l’adresse du destinataire, le message (assurez-vous de copier fidèlement les retours à la ligne, les espaces, les tabulations, etc.) et la signature pour vérifier le message. Faites attention à ne pas déduire davantage de la signature que ce qui est contenu dans le message signé même, pour éviter d’être trompé par une attaque de l’intercepteur. Notez que cela ne fait que prouver que le signataire reçoit avec l’adresse et ne peut pas prouver la provenance d’une transaction.</translation> </message> <message> <source>The Bitcoin address the message was signed with</source> - <translation>L’adresse Bitcoin avec laquelle le message a été signé</translation> + <translation>L’adresse Bitcoin avec laquelle le message a été signé</translation> </message> <message> <source>The signed message to verify</source> @@ -2659,7 +2844,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation>Vérifier le message pour s’assurer qu’il a été signé avec l’adresse Bitcoin indiquée</translation> + <translation>Vérifier le message pour s’assurer qu’il a été signé avec l’adresse Bitcoin indiquée</translation> </message> <message> <source>Verify &Message</source> @@ -2881,7 +3066,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Debug information</source> - <translation>Informations de débogage</translation> + <translation>Renseignements de débogage</translation> </message> <message> <source>Transaction</source> @@ -3074,7 +3259,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Enter address, transaction id, or label to search</source> - <translation>Saisir l’adresse, l’ID de transaction ou l’étiquette à chercher</translation> + <translation>Saisissez l’adresse, l’ID de transaction ou l’étiquette à chercher</translation> </message> <message> <source>Min amount</source> @@ -3185,7 +3370,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <name>UnitDisplayStatusBarControl</name> <message> <source>Unit to show amounts in. Click to select another unit.</source> - <translation>Unité d’affichage des montants. Cliquer pour choisir une autre unité.</translation> + <translation>Unité d’affichage des montants. Cliquez pour choisir une autre unité.</translation> </message> </context> <context> @@ -3202,12 +3387,28 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Fermer le porte-monnaie trop longtemps peut impliquer de devoir resynchroniser la chaîne entière si l’élagage est activé.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Fermer tous les porte-monnaie</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Voulez-vous vraiment fermer tous les porte-monnaie ?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Aucun porte-monnaie n’a été chargé.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Aucun porte-monnaie n’a été chargé. +Accédez à Fichier > Ouvrir un porte-monnaie pour en charger un. +– OU –</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Créer un nouveau porte-monnaie</translation> </message> </context> <context> @@ -3226,23 +3427,23 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Do you want to increase the fee?</source> - <translation>Souhaitez-vous augmenter les frais ?</translation> + <translation>Voulez-vous augmenter les frais ?</translation> </message> <message> <source>Do you want to draft a transaction with fee increase?</source> - <translation>Souhaitez-vous créer une ébauche de transaction avec une augmentation des frais ?</translation> + <translation>Voulez-vous créer une ébauche de transaction avec une augmentation des frais ?</translation> </message> <message> <source>Current fee:</source> - <translation>Frais actuels :</translation> + <translation>Frais actuels :</translation> </message> <message> <source>Increase:</source> - <translation>Augmentation :</translation> + <translation>Augmentation :</translation> </message> <message> <source>New fee:</source> - <translation>Nouveaux frais :</translation> + <translation>Nouveaux frais :</translation> </message> <message> <source>Confirm fee bump</source> @@ -3280,6 +3481,30 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Exporter les données de l’onglet actuel vers un fichier</translation> </message> <message> + <source>Error</source> + <translation>Erreur</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Impossible de décoder la TBSP du presse-papiers (le Base64 est invalide)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Charger les données de la transaction</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Transaction signée partiellement (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>Le fichier de la TBSP doit être inférieur à 100 Mio</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Impossible de décoder la TBSP</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Sauvegarder le porte-monnaie</translation> </message> @@ -3312,7 +3537,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <name>bitcoin-core</name> <message> <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> - <translation>Distribué sous la licence MIT d’utilisation d’un logiciel. Consulter le fichier joint %s ou %s</translation> + <translation>Distribué sous la licence MIT d’utilisation d’un logiciel, consultez le fichier joint %s ou %s</translation> </message> <message> <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> @@ -3320,11 +3545,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </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>Élagage : la dernière synchronisation de porte-monnaie va par-delà les données élaguées. Vous devez -reindex (réindexer, télécharger de nouveau toute la chaîne de blocs en cas de nœud élagué)</translation> - </message> - <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Erreur : Une erreur interne fatale s’est produite. Voir debug.log pour plus de détails</translation> + <translation>Élagage : la dernière synchronisation de porte-monnaie va par-delà les données élaguées. Vous devez -reindex (réindexer, télécharger de nouveau toute la chaîne de blocs en cas de nœud élagué)</translation> </message> <message> <source>Pruning blockstore...</source> @@ -3332,15 +3553,11 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Unable to start HTTP server. See debug log for details.</source> - <translation>Impossible de démarrer le serveur HTTP. Voir le journal de débogage pour plus de détails.</translation> + <translation>Impossible de démarrer le serveur HTTP. Consultez le journal de débogage pour plus de précisions.</translation> </message> <message> <source>The %s developers</source> - <translation>Les développeurs de %s</translation> - </message> - <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Impossible de générer une clé d’adresse de monnaie. Il n’y a pas de clés dans la réserve de clés et il est impossible d’en générer.</translation> + <translation>Les développeurs de %s</translation> </message> <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> @@ -3352,19 +3569,35 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> - <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> + <translation>Erreur de lecture de %s. Toutes les clés ont été lues correctement, mais les données de la transaction ou les entrées du carnet d’adresses sont peut-être manquantes ou incorrectes.</translation> + </message> + <message> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation>Plus d’une adresse onion de liaison est indiquée. %s sera utilisée pour le service onion de Tor créé automatiquement.</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> + <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> <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> - <translation>Si vous trouvez %s utile, vous pouvez y contribuer. Vous trouverez plus de renseignements au sujet du logiciel sur %s.</translation> + <translation>Si vous trouvez %s utile, veuillez y contribuer. Pour de plus de précisions sur le logiciel, rendez-vous sur %s.</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase : échec de préparation de l’instruction pour récupérer la version du schéma de porte-monnaie sqlite : %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>SQLiteDatabase : échec de préparation de l’instruction pour récupérer l’ID de l’application : %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <translation>SQLiteDatabase : la version %d du schéma de porte-monnaie sqlite est inconnue. Seule la version %d est prise en charge</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>La base de données de blocs contient un bloc qui semble provenir du futur. Cela pourrait être causé par la date et l’heure erronées de votre ordinateur. Ne reconstruisez la base de données de blocs que si vous êtes certain que la date et l’heure de votre ordinateur sont justes.</translation> + <translation>La base de données de blocs comprend un bloc qui semble provenir du futur. Cela pourrait être causé par la date et l’heure erronées de votre ordinateur. Ne reconstruisez la base de données de blocs que si vous êtes certain que la date et l’heure de votre ordinateur sont justes.</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> @@ -3384,19 +3617,11 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> - <translation>Avertissement : Le réseau ne semble pas totalement d’accord ! Certains mineurs semblent éprouver des problèmes.</translation> + <translation>Avertissement : Le réseau ne semble pas totalement d’accord. Certains mineurs semblent éprouver des problèmes.</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>Avertissement : Nous ne semblons pas être en accord complet avec nos pairs ! Une mise à niveau pourrait être nécessaire pour vous ou pour d’autres nœuds du réseau.</translation> - </message> - <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d des 100 derniers blocs ont une version inattendue</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrompu, la récupération a échoué</translation> + <translation>Avertissement : Nous ne semblons pas être en accord complet avec nos pairs. Une mise à niveau pourrait être nécessaire pour vous ou pour d’autres nœuds du réseau.</translation> </message> <message> <source>-maxmempool must be at least %d MB</source> @@ -3440,7 +3665,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Error initializing wallet database environment %s!</source> - <translation>Erreur d’initialisation de l’environnement de la base de données du porte-monnaie %s !</translation> + <translation>Erreur d’initialisation de l’environnement de la base de données du porte-monnaie %s.</translation> </message> <message> <source>Error loading %s</source> @@ -3475,6 +3700,10 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Échec de réanalyse du porte-monnaie lors de l’initialisation</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Échec de vérification de la base de données</translation> + </message> + <message> <source>Importing...</source> <translation>Importation…</translation> </message> @@ -3488,19 +3717,43 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Invalid P2P permission: '%s'</source> - <translation>Permission P2P invalide : '%s'</translation> + <translation>L’autorisation P2P est invalide : « %s »</translation> </message> <message> <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation>Montant invalide pour -%s=<amount> : « %s »</translation> + <translation>Le montant est invalide pour -%s=<amount> : « %s »</translation> </message> <message> <source>Invalid amount for -discardfee=<amount>: '%s'</source> - <translation>Montant invalide pour -discardfee=<amount> : « %s »</translation> + <translation>Le montant est invalide pour -discardfee=<amount> : « %s »</translation> </message> <message> <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> - <translation>Montant invalide pour -fallbackfee=<amount> : « %s »</translation> + <translation>Le montant est invalide pour -fallbackfee=<amount> : « %s »</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase : échec d’exécution de l’instruction pour vérifier la base de données : %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase : échec de récupération de la version du schéma de porte-monnaie sqlite : %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation>SQLiteDatabase : échec de récupération de l’ID de l’application : %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase : échec de préparation de l’instruction pour vérifier la base de données : %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase : échec de lecture de l’erreur de vérification de la base de données : %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase : l’ID de l’application est inattendu. %u était attendu, %u été retourné</translation> </message> <message> <source>Specified blocks directory "%s" does not exist.</source> @@ -3508,11 +3761,11 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Unknown address type '%s'</source> - <translation>Type d’adresse inconnu '%s'</translation> + <translation>Le type d’adresse est inconnu « %s »</translation> </message> <message> <source>Unknown change type '%s'</source> - <translation>Type de monnaie inconnu '%s'</translation> + <translation>Le type de monnaie est inconnu « %s »</translation> </message> <message> <source>Upgrading txindex database</source> @@ -3523,10 +3776,6 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Chargement des adresses P2P…</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Erreur : L’espace disque est trop faible !</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Chargement de la liste d’interdiction…</translation> </message> @@ -3576,7 +3825,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>User Agent comment (%s) contains unsafe characters.</source> - <translation>Le commentaire d’agent utilisateur (%s) contient des caractères dangereux.</translation> + <translation>Le commentaire de l’agent utilisateur (%s) comporte des caractères dangereux.</translation> </message> <message> <source>Verifying blocks...</source> @@ -3588,21 +3837,53 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Error: Listening for incoming connections failed (listen returned error %s)</source> - <translation>Erreur : L’écoute des connexions entrantes a échoué (l’écoute a retourné l’erreur %s)</translation> + <translation>Erreur : L’écoute des connexions entrantes a échoué (l’écoute a retourné l’erreur %s)</translation> + </message> + <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s est corrompu. Essayez l’outil bitcoin-wallet pour le sauver ou restaurez une sauvegarde.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Impossible de mettre à niveau un porte-monnaie divisé non-HD sans mettre à niveau pour prendre en charge la réserve de clés antérieure à la division. Veuillez utiliser la version 169900 ou ne pas indiquer de version.</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>Montant invalide pour -maxtxfee=<amount> : « %s » (doit être au moins les frais minrelay de %s pour prévenir le blocage des transactions)</translation> + <translation>Le montant est invalide pour -maxtxfee=<amount> : « %s » (doit être au moins les frais minrelay de %s pour prévenir le blocage des transactions)</translation> </message> <message> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation>Le montant de la transaction est trop bas pour être envoyé une fois que les frais ont été déduits</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Cette erreur pourrait survenir si ce porte-monnaie n’avait pas été fermé proprement et s’il avait été chargé en dernier avec une nouvelle version de Berkeley DB. Si c’est le cas, veuillez utiliser le logiciel qui a chargé ce porte-monnaie en dernier.</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Les frais maximaux de transaction que vous payez (en plus des frais habituels) afin de prioriser une dépense non partielle plutôt qu’une sélection normale de pièces.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Une adresse de monnaie est nécessaire à la transaction, mais nous ne pouvons pas la générer. Veuillez d’abord appeler « keypoolrefill ».</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>Vous devez reconstruire la base de données en utilisant -reindex afin de revenir au mode sans élagage. Cela retéléchargera complètement la chaîne de blocs.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Une erreur interne fatale est survenue. Consultez debug.log pour plus de précisions</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Impossible de définir -peerblockfilters sans -blockfilterindex</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>L’espace disque est trop faible !</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Erreur de lecture de la base de données, fermeture en cours.</translation> </message> @@ -3615,26 +3896,38 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Erreur : Il reste peu d’espace disque sur %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Erreur : La réserve de clés est épuisée, veuillez d’abord appeler « keypoolrefill »</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Le taux de frais (%s) est inférieur au taux minimal de frais défini (%s)</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> - <translation>Adresse ou nom d’hôte -onion invalide : « %s »</translation> + <translation>L’adresse -onion ou le nom d’hôte sont invalides : « %s »</translation> </message> <message> <source>Invalid -proxy address or hostname: '%s'</source> - <translation>Adresse ou nom d’hôte -proxy invalide : « %s »</translation> + <translation>L’adresse -proxy ou le nom d’hôte sont invalides : « %s »</translation> </message> <message> <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> - <translation>Montant invalide pour -paytxfee=<montant> : « %s » (doit être au moins %s)</translation> + <translation>Le montant est invalide pour -paytxfee=<montant> : « %s » (doit être au moins %s)</translation> </message> <message> <source>Invalid netmask specified in -whitelist: '%s'</source> - <translation>Masque réseau invalide indiqué dans -whitelist : « %s »</translation> + <translation>Le masque réseau indiqué dans -whitelist est invalide : « %s »</translation> </message> <message> <source>Need to specify a port with -whitebind: '%s'</source> <translation>Un port doit être précisé avec -whitebind : « %s »</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Aucun serveur mandataire n’est indiqué. Utilisez -proxy=<ip> ou -proxy=<ip:port></translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Le mode élagage n’est pas compatible avec -blockfilterindex.</translation> </message> @@ -3690,7 +3983,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Unable to create the PID file '%s': %s</source> - <translation>Impossible de créer le fichier PID '%s' : %s</translation> + <translation>Impossible de créer le fichier PID « %s » : %s</translation> </message> <message> <source>Unable to generate initial keys</source> @@ -3698,7 +3991,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Unknown -blockfilterindex value %s.</source> - <translation>Valeur -blockfilterindex inconnue %s.</translation> + <translation>La valeur -blockfilterindex %s est inconnue.</translation> </message> <message> <source>Verifying wallet(s)...</source> @@ -3709,12 +4002,8 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>Avertissement : De nouvelles règles inconnues ont été activées (bit de version %i).</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Supprimer toutes les transactions du porte-monnaie…</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> - <translation>La valeur -maxtxfee est très élevée ! Des frais aussi élevés pourraient être payés en une seule transaction.</translation> + <translation>La valeur -maxtxfee est très élevée. Des frais aussi élevés pourraient être payés en une seule transaction.</translation> </message> <message> <source>This is the transaction fee you may pay when fee estimates are not available.</source> @@ -3725,12 +4014,8 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par <translation>La taille totale de la chaîne de version de réseau (%i) dépasse la longueur maximale (%i). Réduire le nombre ou la taille des commentaires uacomments.</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>Avertissement : Le fichier du porte-monnaie est corrompu, les données ont été récupérées ! Le fichier %s original a été enregistré en tant que %s dans %s ; si votre solde ou vos transactions sont incorrects, vous devriez restaurer une sauvegarde.</translation> - </message> - <message> <source>%s is set very high!</source> - <translation>La valeur %s est très élevée !</translation> + <translation>La valeur %s est très élevée.</translation> </message> <message> <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> @@ -3766,17 +4051,13 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> - <translation>Réseau inconnu précisé dans -onlynet : « %s »</translation> + <translation>Un réseau inconnu est indiqué dans -onlynet : « %s »</translation> </message> <message> <source>Insufficient funds</source> <translation>Fonds insuffisants</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>Impossible de mettre à niveau un porte-monnaie divisé non-HD sans mettre à niveau pour prendre en charge la réserve de clés antérieure à la division. Veuillez utiliser -upgradewallet=169900 ou -upgradewallet sans indiquer de version.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Échec d’estimation des frais. L’option de frais de repli est désactivée. Attendez quelques blocs ou activez -fallbackfee.</translation> </message> @@ -3786,7 +4067,7 @@ Note : Les frais étant calculés par octet, des frais de « 100 satoshis par </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation>Impossible d’écrire dans le répertoire de données '%s' ; veuillez vérifier les droits.</translation> + <translation>Impossible d’écrire dans le répertoire de données « %s » ; veuillez vérifier les droits.</translation> </message> <message> <source>Loading block index...</source> diff --git a/src/qt/locale/bitcoin_gl_ES.ts b/src/qt/locale/bitcoin_gl_ES.ts new file mode 100644 index 0000000000..2438aff7cd --- /dev/null +++ b/src/qt/locale/bitcoin_gl_ES.ts @@ -0,0 +1,3743 @@ +<TS language="gl_ES" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>Fai Click co botón dereito para editar o enderezo ou etiqueta</translation> + </message> + <message> + <source>Create a new address</source> + <translation>Crea un novo enderezo</translation> + </message> + <message> + <source>&New</source> + <translation>&Novo</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Copia o enderezo seleccionado ao portapapeis do sistema</translation> + </message> + <message> + <source>&Copy</source> + <translation>&Copiar</translation> + </message> + <message> + <source>C&lose</source> + <translation>Pechar</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>Borra o enderezo seleccionado actualmente da lista</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>Introduce un enderezo ou etiqueta para buscar</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Exporta os datos na pestana actual a un ficheiro</translation> + </message> + <message> + <source>&Export</source> + <translation>Exportar</translation> + </message> + <message> + <source>&Delete</source> + <translation>Borrar</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>Selecciona o enderezo ó que enviar moedas</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>Selecciona o enderezo do que recibir moedas</translation> + </message> + <message> + <source>C&hoose</source> + <translation>Selecciona</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Enderezos de envío</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Enderezos de recepció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>Estes son os teus enderezos de Bitcoin para enviar pagamentos. Asegurate sempre de comprobar a cantidade e maila dirección antes de enviar moedas.</translation> + </message> + <message> + <source>&Copy Address</source> + <translation>Copiar Enderezo</translation> + </message> + <message> + <source>Copy &Label</source> + <translation>Copia Etiqueta</translation> + </message> + <message> + <source>&Edit</source> + <translation>Edita</translation> + </message> + <message> + <source>Export Address List</source> + <translation>Exporta a Lista de Enderezos</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Ficheiro Separado por Comas (*.csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Exportación Fallida</translation> + </message> + <message> + <source>There was an error trying to save the address list to %1. Please try again.</source> + <translation>Houbo un erro tentando gardar a lista de enderezos en %1. Por favor proba de novo.</translation> + </message> +</context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>Etiqueta</translation> + </message> + <message> + <source>Address</source> + <translation>Enderezo</translation> + </message> + <message> + <source>(no label)</source> + <translation>(sin etiqueta)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>Diálogo de Frase Contrasinal</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>Introduce a frase contrasinal</translation> + </message> + <message> + <source>New passphrase</source> + <translation>Nova frase contrasinal</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Repite a frase contrasinal</translation> + </message> + <message> + <source>Show passphrase</source> + <translation>Mostra frase contrasinal</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Encriptar carteira</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>Esta operación necesita da túa frase contrasinal para desbloqueares a carteira.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Desbloquear carteira</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>Esta operación necesita da túa frase contrasinal para desbloquea a carteira.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Desencriptar carteira</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Cambiar frase contrasinal</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Confirmar encriptación da carteira</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>Aviso: Si encriptas a túa carteira e perdes a túa frase contrasinal, <b>PERDERÁS TODOS OS TEUS BITCOINS</b>!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>¿Seguro que queres encriptar a túa carteira?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Carteira encriptada</translation> + </message> + <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Introduce unha nova frase contrasinal para a carteira.<br/>Por favor utiliza una frase contrasinal que <b>teña dez ou máis caracteres aleatorios</b>, ou <b>oito ou máis palabras</b>.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Introduce a frase contrasinal anterior mais a nova frase contrasinal para a carteira.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Recorda que encriptar a tua carteira non protexe completamente que os teus bitcoins poidan ser roubados por malware que afecte ó teu computador.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Carteira para ser encriptada</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>A túa carteira vai a ser encriptada.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>A túa carteira está agora encriptada.</translation> + </message> + <message> + <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source> + <translation>IMPORTANTE: Calquera copia de respaldo que tiveras feita da túa carteira debería ser sustituída por unha nova copia xerada a partires da túa nova carteira encriptada. Por razóns de seguridade, as copias de respaldo da túa carteira sin encriptar non se poderán usar unha vez que empeces a utilizar a túa nova carteira encriptada.</translation> + </message> + <message> + <source>Wallet encryption failed</source> + <translation>Error na Encriptación da carteira </translation> + </message> + <message> + <source>Wallet encryption failed due to an internal error. Your wallet was not encrypted.</source> + <translation>A encriptación da carteira fallou debido a un erro interno. A túa carteira no foi encriptada.</translation> + </message> + <message> + <source>The supplied passphrases do not match.</source> + <translation>As frases contrasinal introducidas non coinciden.</translation> + </message> + <message> + <source>Wallet unlock failed</source> + <translation>Desbloqueo de carteira fallido</translation> + </message> + <message> + <source>The passphrase entered for the wallet decryption was incorrect.</source> + <translation>A frase contrasinal introducida para o desencriptamento da carteira é incorrecto.</translation> + </message> + <message> + <source>Wallet decryption failed</source> + <translation>Fallou o desencriptado da carteira</translation> + </message> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>A frase contrasinal da carteira mudouse correctamente.</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>Aviso: ¡A tecla Bloq. Mayús está activada!</translation> + </message> +</context> +<context> + <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Máscara de rede</translation> + </message> + <message> + <source>Banned Until</source> + <translation>Vedado ata</translation> + </message> +</context> +<context> + <name>BitcoinGUI</name> + <message> + <source>Sign &message...</source> + <translation>Firma &a mensaxe...</translation> + </message> + <message> + <source>Synchronizing with network...</source> + <translation>Sincronizando ca rede...</translation> + </message> + <message> + <source>&Overview</source> + <translation>&visión xeral</translation> + </message> + <message> + <source>Show general overview of wallet</source> + <translation>Mostra una visión xeral da carteira</translation> + </message> + <message> + <source>&Transactions</source> + <translation>&Transaccións</translation> + </message> + <message> + <source>Browse transaction history</source> + <translation>Busca no historial de transaccións</translation> + </message> + <message> + <source>E&xit</source> + <translation>S&aír</translation> + </message> + <message> + <source>Quit application</source> + <translation>Saír da aplicación</translation> + </message> + <message> + <source>&About %1</source> + <translation>&A cerca de %1</translation> + </message> + <message> + <source>Show information about %1</source> + <translation>Mostra información acerca de %1</translation> + </message> + <message> + <source>About &Qt</source> + <translation>Acerca de &Qt</translation> + </message> + <message> + <source>Show information about Qt</source> + <translation>Mostra información acerca de Qt</translation> + </message> + <message> + <source>&Options...</source> + <translation>&Opcións...</translation> + </message> + <message> + <source>Modify configuration options for %1</source> + <translation>Modifica as opcións de configuración de %1</translation> + </message> + <message> + <source>&Encrypt Wallet...</source> + <translation>&Encriptar Carteira...</translation> + </message> + <message> + <source>&Backup Wallet...</source> + <translation>&Respaldar Carteira...</translation> + </message> + <message> + <source>&Change Passphrase...</source> + <translation>&Mudar frase contrasinal...</translation> + </message> + <message> + <source>Open &URI...</source> + <translation>Abrir &URI...</translation> + </message> + <message> + <source>Create Wallet...</source> + <translation>Crear Carteira...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crear unha nova carteira</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Carteira:</translation> + </message> + <message> + <source>Click to disable network activity.</source> + <translation>Fai click para desactivar a actividade da rede.</translation> + </message> + <message> + <source>Network activity disabled.</source> + <translation>Actividade da rede desactivada.</translation> + </message> + <message> + <source>Click to enable network activity again.</source> + <translation>Fai click para activar a activade da red de novo.</translation> + </message> + <message> + <source>Syncing Headers (%1%)...</source> + <translation>Sincronizando Cabeceiras (%1%)...</translation> + </message> + <message> + <source>Reindexing blocks on disk...</source> + <translation>Reindexando bloques en disco...</translation> + </message> + <message> + <source>Proxy is <b>enabled</b>: %1</source> + <translation>Proxy <b>activado</b>: %1</translation> + </message> + <message> + <source>Send coins to a Bitcoin address</source> + <translation>Envía moedas a un enderezo de Bitcoin</translation> + </message> + <message> + <source>Backup wallet to another location</source> + <translation>Respalda a carteira noutro destino</translation> + </message> + <message> + <source>Change the passphrase used for wallet encryption</source> + <translation>Cambia a frase contrasinal usada para a encriptación da carteira</translation> + </message> + <message> + <source>&Verify message...</source> + <translation>&Verifica a mensaxe...</translation> + </message> + <message> + <source>&Send</source> + <translation>&Envía</translation> + </message> + <message> + <source>&Receive</source> + <translation>&Recibir</translation> + </message> + <message> + <source>&Show / Hide</source> + <translation>&Mostra / Agocha</translation> + </message> + <message> + <source>Show or hide the main Window</source> + <translation>Mostra ou agocha a xanela principal</translation> + </message> + <message> + <source>Encrypt the private keys that belong to your wallet</source> + <translation>Encripta as claves privadas que pertencen á túa carteira</translation> + </message> + <message> + <source>Sign messages with your Bitcoin addresses to prove you own them</source> + <translation>Asina mensaxes cos teus enderezos de Bitcoin para probar que che pertencen</translation> + </message> + <message> + <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> + <translation>Verifica mensaxes para asegurar que foron asinados cos enderezos de Bitcoin especificados</translation> + </message> + <message> + <source>&File</source> + <translation>&Arquivo</translation> + </message> + <message> + <source>&Settings</source> + <translation>&Opcións</translation> + </message> + <message> + <source>&Help</source> + <translation>&Axuda</translation> + </message> + <message> + <source>Tabs toolbar</source> + <translation>Barra de ferramentas das pestanas</translation> + </message> + <message> + <source>Request payments (generates QR codes and bitcoin: URIs)</source> + <translation>Solicita pagamentos (xera un código QR e bitocin : URIs)</translation> + </message> + <message> + <source>Show the list of used sending addresses and labels</source> + <translation>Mostra a lista de enderezos de envío e etiquetas usadas</translation> + </message> + <message> + <source>Show the list of used receiving addresses and labels</source> + <translation>Mostra a lista de enderezos de recepción e etiquetas usadas</translation> + </message> + <message> + <source>&Command-line options</source> + <translation>&Opcións de comando</translation> + </message> + <message numerus="yes"> + <source>%n active connection(s) to Bitcoin network</source> + <translation><numerusform>%n active connection to Bitcoin network</numerusform><numerusform>%n Conexións activas cara a rede de Bitcoin</numerusform></translation> + </message> + <message> + <source>Indexing blocks on disk...</source> + <translation>Indexando bloques no disco...</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Procesando bloques no disco...</translation> + </message> + <message numerus="yes"> + <source>Processed %n block(s) of transaction history.</source> + <translation><numerusform>Processed %n block of transaction history.</numerusform><numerusform>Procesando %n bloques do historial de transaccións.</numerusform></translation> + </message> + <message> + <source>%1 behind</source> + <translation>%1 tras</translation> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation>O último bloque recibido foi xerado fai %1.</translation> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Transaccións despois desta non serán aínda visibles.</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Warning</source> + <translation>Aviso</translation> + </message> + <message> + <source>Information</source> + <translation>Información</translation> + </message> + <message> + <source>Up to date</source> + <translation>Actualizado</translation> + </message> + <message> + <source>Node window</source> + <translation>Xanela de Nodo</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Abre a consola de depuración e diagnostico do nodo</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation>&Enderezos de envío</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Enderezos de recepción</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation>Abre una URI de Bitcoin</translation> + </message> + <message> + <source>Open Wallet</source> + <translation>Abrir carteira</translation> + </message> + <message> + <source>Open a wallet</source> + <translation>Abrir unha carteira</translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>Pechar carteira...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>Pechar carteira</translation> + </message> + <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Mostra a %1 mensaxe de axuda para obter unha lista cas posibles opcións de línea de comando de Bitcoin </translation> + </message> + <message> + <source>default wallet</source> + <translation>Carteira por defecto</translation> + </message> + <message> + <source>No wallets available</source> + <translation>Non hai carteiras dispoñibles</translation> + </message> + <message> + <source>&Window</source> + <translation>&Xanela</translation> + </message> + <message> + <source>Minimize</source> + <translation>Minimizar</translation> + </message> + <message> + <source>Zoom</source> + <translation>Zoom</translation> + </message> + <message> + <source>Main Window</source> + <translation>Xanela Principal</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 cliente</translation> + </message> + <message> + <source>Connecting to peers...</source> + <translation>Connectando con compañeiros...</translation> + </message> + <message> + <source>Catching up...</source> + <translation>Poñéndose ao día...</translation> + </message> + <message> + <source>Error: %1</source> + <translation>Error: %1</translation> + </message> + <message> + <source>Warning: %1</source> + <translation>Aviso: %1</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>Data: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Cantidade: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>Carteira: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Escribe: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Etiqueta: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Enderezo: %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation>Transacción enviada</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>Transacción entrante</translation> + </message> + <message> + <source>HD key generation is <b>enabled</b></source> + <translation>A xeración de clave HD está <b>activada</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>A xeración de clave HD está <b>desactivada</b></translation> + </message> + <message> + <source>Private key <b>disabled</b></source> + <translation>Clave privada <b>desactivada</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation>A carteira está <b>encrypted</b> e actualmente <b>desbloqueada</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation>A carteira está <b>encriptada</b> e actualmente <b>bloqueada</b></translation> + </message> + </context> +<context> + <name>CoinControlDialog</name> + <message> + <source>Coin Selection</source> + <translation>Selección de moeda</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Cantidade:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Cantidade:</translation> + </message> + <message> + <source>Fee:</source> + <translation>taxa:</translation> + </message> + <message> + <source>Dust:</source> + <translation>po:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>Despois de taxas:</translation> + </message> + <message> + <source>Change:</source> + <translation>Cambio:</translation> + </message> + <message> + <source>(un)select all</source> + <translation>(de)seleccionar todo</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Modo en árbore</translation> + </message> + <message> + <source>List mode</source> + <translation>Modo en Lista</translation> + </message> + <message> + <source>Amount</source> + <translation>Cantidade</translation> + </message> + <message> + <source>Received with label</source> + <translation>Recibida con etiqueta</translation> + </message> + <message> + <source>Received with address</source> + <translation>Recibida con enderezo</translation> + </message> + <message> + <source>Date</source> + <translation>Data</translation> + </message> + <message> + <source>Confirmations</source> + <translation>Confirmacións</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Confirmada</translation> + </message> + <message> + <source>Copy address</source> + <translation>Copiar enderezo</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copiar etiqueta</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copiar cantidade</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Copiar ID da transacción</translation> + </message> + <message> + <source>Lock unspent</source> + <translation>Bloquear o non gastado</translation> + </message> + <message> + <source>Unlock unspent</source> + <translation>Desbloquear o non gastado</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Copiar cantidade</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Copiar taxa</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Copiar despois de taxa</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Copiar bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Copiar po</translation> + </message> + <message> + <source>Copy change</source> + <translation>Copiar cambio</translation> + </message> + <message> + <source>(%1 locked)</source> + <translation>(%1 bloqueado)</translation> + </message> + <message> + <source>yes</source> + <translation>sí</translation> + </message> + <message> + <source>no</source> + <translation>no</translation> + </message> + <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>Esta etiqueta tórnase vermella se algún receptor recibe unha cantidade máis pequena que o actual límite de po.</translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Pode variar +/- %1 satoshi(s) por entrada.</translation> + </message> + <message> + <source>(no label)</source> + <translation>(sen etiqueta)</translation> + </message> + <message> + <source>change from %1 (%2)</source> + <translation>Cambia de %1 a (%2)</translation> + </message> + <message> + <source>(change)</source> + <translation>(Cambia)</translation> + </message> +</context> +<context> + <name>CreateWalletActivity</name> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Creando Carteira <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Creación de carteira fallida</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Creación de carteira con aviso</translation> + </message> +</context> +<context> + <name>CreateWalletDialog</name> + <message> + <source>Create Wallet</source> + <translation>Crea unha Carteira</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Nome da Carteira</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Encripta a carteira. A carteira sera encriptada cunha frase contrasinal que tú elixas.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Encriptar Carteira</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Desactiva as claves privadas para esta carteira. Carteiras con claves privadas desactivadas non terán claves privadas e polo tanto non poderan ter unha semente HD ou claves privadas importadas. Esto é ideal para carteiras de solo visualización.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Desactivar Claves Privadas</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Crear unha Carteira en blanco. As carteiras en blanco non teñen inicialmente claves privadas ou scripts. As claves privadas poden ser importadas ou unha semente HD poder ser configurada, máis adiante.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Crea unha Carteira en Blanco</translation> + </message> + <message> + <source>Create</source> + <translation>Crea</translation> + </message> +</context> +<context> + <name>EditAddressDialog</name> + <message> + <source>Edit Address</source> + <translation>Editar Enderezo</translation> + </message> + <message> + <source>&Label</source> + <translation>&Etiqueta</translation> + </message> + <message> + <source>The label associated with this address list entry</source> + <translation>A etiqueta asociada con esta entrada na lista de enderezos</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>O enderezo asociado con esta entrada na lista de enderezos. Solo pode ser modificado por enderezos de envío.</translation> + </message> + <message> + <source>&Address</source> + <translation>&Enderezo</translation> + </message> + <message> + <source>New sending address</source> + <translation>Novo enderezo de envío</translation> + </message> + <message> + <source>Edit receiving address</source> + <translation>Editar enderezo de recepción</translation> + </message> + <message> + <source>Edit sending address</source> + <translation>Editar enderezo de envío</translation> + </message> + <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <translation>O enderezo introducido "%1" non é un enderezo de Bitcoin válido.</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>O enderezo "%1" xa existe como un enderezo de recepción ca etiqueta "%2" polo que non pode ser añadido como un enderezo de envío.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>O enderezo introducido "%1" xa existe na axenda de enderezos ca etiqueta "%2".</translation> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Non se puido desbloquear a carteira.</translation> + </message> + <message> + <source>New key generation failed.</source> + <translation>New key generation failed.</translation> + </message> +</context> +<context> + <name>FreespaceChecker</name> + <message> + <source>A new data directory will be created.</source> + <translation>A new data directory will be created.</translation> + </message> + <message> + <source>name</source> + <translation>name</translation> + </message> + <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation>Directory already exists. Add %1 if you intend to create a new directory here.</translation> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation>Path already exists, and is not a directory.</translation> + </message> + <message> + <source>Cannot create data directory here.</source> + <translation>Cannot create data directory here.</translation> + </message> +</context> +<context> + <name>HelpMessageDialog</name> + <message> + <source>version</source> + <translation>version</translation> + </message> + <message> + <source>About %1</source> + <translation>About %1</translation> + </message> + <message> + <source>Command-line options</source> + <translation>Command-line options</translation> + </message> +</context> +<context> + <name>Intro</name> + <message> + <source>Welcome</source> + <translation>Welcome</translation> + </message> + <message> + <source>Welcome to %1.</source> + <translation>Welcome to %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>As this is the first time the program is launched, you can choose where %1 will store its data.</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>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.</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</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>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.</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>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> + </message> + <message> + <source>Use the default data directory</source> + <translation>Use the default data directory</translation> + </message> + <message> + <source>Use a custom data directory:</source> + <translation>Use a custom data directory:</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Discard blocks after verification, except most recent %1 GB (prune)</translation> + </message> + <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>At least %1 GB of data will be stored in this directory, and it will grow over time.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Approximately %1 GB of data will be stored in this directory.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 will download and store a copy of the Bitcoin block chain.</translation> + </message> + <message> + <source>The wallet will also be stored in this directory.</source> + <translation>The wallet will also be stored in this directory.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>Error: Specified data directory "%1" cannot be created.</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>%n GB of free space available</numerusform><numerusform>%n GB of free space available</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(of %n GB needed)</numerusform><numerusform>(of %n GB needed)</numerusform></translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB needed for full chain)</numerusform><numerusform>(%n GB needed for full chain)</numerusform></translation> + </message> +</context> +<context> + <name>ModalOverlay</name> + <message> + <source>Form</source> + <translation>Form</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>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.</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>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</translation> + </message> + <message> + <source>Number of blocks left</source> + <translation>Number of blocks left</translation> + </message> + <message> + <source>Unknown...</source> + <translation>Unknown...</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>Progress</source> + <translation>Progress</translation> + </message> + <message> + <source>Progress increase per hour</source> + <translation>Progress increase per hour</translation> + </message> + <message> + <source>calculating...</source> + <translation>calculating...</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation>Estimated time left until synced</translation> + </message> + <message> + <source>Hide</source> + <translation>Hide</translation> + </message> + <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Unknown. Syncing Headers (%1, %2%)...</translation> + </message> +</context> +<context> + <name>OpenURIDialog</name> + <message> + <source>Open bitcoin URI</source> + <translation>Open bitcoin URI</translation> + </message> + <message> + <source>URI:</source> + <translation>URI:</translation> + </message> +</context> +<context> + <name>OpenWalletActivity</name> + <message> + <source>Open wallet failed</source> + <translation>Open wallet failed</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Open wallet warning</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> + <message> + <source>Opening Wallet <b>%1</b>...</source> + <translation>Opening Wallet <b>%1</b>...</translation> + </message> +</context> +<context> + <name>OptionsDialog</name> + <message> + <source>Options</source> + <translation>Options</translation> + </message> + <message> + <source>&Main</source> + <translation>&Main</translation> + </message> + <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Automatically start %1 after logging in to the system.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Start %1 on system login</translation> + </message> + <message> + <source>Size of &database cache</source> + <translation>Size of &database cache</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation>Number of script &verification threads</translation> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>IP address of the proxy (e.g. 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>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</translation> + </message> + <message> + <source>Hide the icon from the system tray.</source> + <translation>Hide the icon from the system tray.</translation> + </message> + <message> + <source>&Hide tray icon</source> + <translation>&Hide tray icon</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>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.</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>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 |.</translation> + </message> + <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Open the %1 configuration file from the working directory.</translation> + </message> + <message> + <source>Open Configuration File</source> + <translation>Open Configuration File</translation> + </message> + <message> + <source>Reset all client options to default.</source> + <translation>Reset all client options to default.</translation> + </message> + <message> + <source>&Reset Options</source> + <translation>&Reset Options</translation> + </message> + <message> + <source>&Network</source> + <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>MiB</source> + <translation>MiB</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = auto, <0 = leave that many cores free)</translation> + </message> + <message> + <source>W&allet</source> + <translation>W&allet</translation> + </message> + <message> + <source>Expert</source> + <translation>Expert</translation> + </message> + <message> + <source>Enable coin &control features</source> + <translation>Enable coin &control features</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>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.</translation> + </message> + <message> + <source>&Spend unconfirmed change</source> + <translation>&Spend unconfirmed change</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>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <translation>Map port using &UPnP</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation>Accept connections from outside.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Allow incomin&g connections</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation>Connect to the Bitcoin network through a SOCKS5 proxy.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Connect through SOCKS5 proxy (default 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 of the proxy (e.g. 9050)</translation> + </message> + <message> + <source>Used for reaching peers via:</source> + <translation>Used for reaching peers via:</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>&Window</translation> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation>Show only a tray icon after minimizing the window.</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation>&Minimize to the tray instead of the taskbar</translation> + </message> + <message> + <source>M&inimize on close</source> + <translation>M&inimize on close</translation> + </message> + <message> + <source>&Display</source> + <translation>&Display</translation> + </message> + <message> + <source>User Interface &language:</source> + <translation>User Interface &language:</translation> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>The user interface language can be set here. This setting will take effect after restarting %1.</translation> + </message> + <message> + <source>&Unit to show amounts in:</source> + <translation>&Unit to show amounts in:</translation> + </message> + <message> + <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> + <translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation> + </message> + <message> + <source>Whether to show coin control features or not.</source> + <translation>Whether to show coin control features or not.</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>&Third party transaction URLs</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Options set in this dialog are overridden by the command line or in the configuration file:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancel</translation> + </message> + <message> + <source>default</source> + <translation>default</translation> + </message> + <message> + <source>none</source> + <translation>none</translation> + </message> + <message> + <source>Confirm options reset</source> + <translation>Confirm options reset</translation> + </message> + <message> + <source>Client restart required to activate changes.</source> + <translation>Client restart required to activate changes.</translation> + </message> + <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>Client will be shut down. Do you want to proceed?</translation> + </message> + <message> + <source>Configuration options</source> + <translation>Configuration options</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>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>The configuration file could not be opened.</source> + <translation>The configuration file could not be opened.</translation> + </message> + <message> + <source>This change would require a client restart.</source> + <translation>This change would require a client restart.</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation>The supplied proxy address is invalid.</translation> + </message> +</context> +<context> + <name>OverviewPage</name> + <message> + <source>Form</source> + <translation>Form</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>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.</translation> + </message> + <message> + <source>Watch-only:</source> + <translation>Watch-only:</translation> + </message> + <message> + <source>Available:</source> + <translation>Available:</translation> + </message> + <message> + <source>Your current spendable balance</source> + <translation>Your current spendable balance</translation> + </message> + <message> + <source>Pending:</source> + <translation>Pending:</translation> + </message> + <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> + </message> + <message> + <source>Immature:</source> + <translation>Immature:</translation> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation>Mined balance that has not yet matured</translation> + </message> + <message> + <source>Balances</source> + <translation>Balances</translation> + </message> + <message> + <source>Total:</source> + <translation>Total:</translation> + </message> + <message> + <source>Your current total balance</source> + <translation>Your current total balance</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>Your current balance in watch-only addresses</translation> + </message> + <message> + <source>Spendable:</source> + <translation>Spendable:</translation> + </message> + <message> + <source>Recent transactions</source> + <translation>Recent transactions</translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Unconfirmed transactions to watch-only addresses</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Mined balance in watch-only addresses that has not yet matured</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Current total balance in watch-only addresses</translation> + </message> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> + </message> + </context> +<context> + <name>PaymentServer</name> + <message> + <source>Payment request error</source> + <translation>Payment request error</translation> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Cannot start bitcoin: click-to-pay handler</translation> + </message> + <message> + <source>URI handling</source> + <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>Cannot process payment request because BIP70 is not supported.</source> + <translation>Cannot process payment request because BIP70 is not supported.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</translation> + </message> + <message> + <source>Invalid payment address %1</source> + <translation>Invalid payment address %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 cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Payment request file handling</translation> + </message> +</context> +<context> + <name>PeerTableModel</name> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node/Service</source> + <translation>Node/Service</translation> + </message> + <message> + <source>NodeId</source> + <translation>NodeId</translation> + </message> + <message> + <source>Ping</source> + <translation>Ping</translation> + </message> + <message> + <source>Sent</source> + <translation>Sent</translation> + </message> + <message> + <source>Received</source> + <translation>Received</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Amount</source> + <translation>Amount</translation> + </message> + <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Enter a Bitcoin address (e.g. %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>None</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 second</numerusform><numerusform>%n seconds</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>%n minute</numerusform><numerusform>%n minutes</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n hour</numerusform><numerusform>%n hours</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n day</numerusform><numerusform>%n days</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n week</numerusform><numerusform>%n weeks</numerusform></translation> + </message> + <message> + <source>%1 and %2</source> + <translation>%1 and %2</translation> + </message> + <message numerus="yes"> + <source>%n year(s)</source> + <translation><numerusform>%n year</numerusform><numerusform>%n years</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>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> + <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 didn't yet exit safely...</translation> + </message> + <message> + <source>unknown</source> + <translation>unknown</translation> + </message> +</context> +<context> + <name>QRImageWidget</name> + <message> + <source>&Save Image...</source> + <translation>&Save Image...</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&Copy Image</translation> + </message> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation>Resulting URI too long, try to reduce the text for label / message.</translation> + </message> + <message> + <source>Error encoding URI into QR Code.</source> + <translation>Error encoding URI into QR Code.</translation> + </message> + <message> + <source>QR code support not available.</source> + <translation>QR code support not available.</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>Save QR Code</translation> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>PNG Image (*.png)</translation> + </message> +</context> +<context> + <name>RPCConsole</name> + <message> + <source>N/A</source> + <translation>N/A</translation> + </message> + <message> + <source>Client version</source> + <translation>Client version</translation> + </message> + <message> + <source>&Information</source> + <translation>&Information</translation> + </message> + <message> + <source>General</source> + <translation>General</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Using BerkeleyDB version</translation> + </message> + <message> + <source>Datadir</source> + <translation>Datadir</translation> + </message> + <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>To specify a non-default location of the data directory use the '%1' option.</translation> + </message> + <message> + <source>Blocksdir</source> + <translation>Blocksdir</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>To specify a non-default location of the blocks directory use the '%1' option.</translation> + </message> + <message> + <source>Startup time</source> + <translation>Startup time</translation> + </message> + <message> + <source>Network</source> + <translation>Network</translation> + </message> + <message> + <source>Name</source> + <translation>Name</translation> + </message> + <message> + <source>Number of connections</source> + <translation>Number of connections</translation> + </message> + <message> + <source>Block chain</source> + <translation>Block chain</translation> + </message> + <message> + <source>Memory Pool</source> + <translation>Memory Pool</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation>Current number of transactions</translation> + </message> + <message> + <source>Memory usage</source> + <translation>Memory usage</translation> + </message> + <message> + <source>Wallet: </source> + <translation>Wallet: </translation> + </message> + <message> + <source>(none)</source> + <translation>(none)</translation> + </message> + <message> + <source>&Reset</source> + <translation>&Reset</translation> + </message> + <message> + <source>Received</source> + <translation>Received</translation> + </message> + <message> + <source>Sent</source> + <translation>Sent</translation> + </message> + <message> + <source>&Peers</source> + <translation>&Peers</translation> + </message> + <message> + <source>Banned peers</source> + <translation>Banned peers</translation> + </message> + <message> + <source>Select a peer to view detailed information.</source> + <translation>Select a peer to view detailed information.</translation> + </message> + <message> + <source>Direction</source> + <translation>Direction</translation> + </message> + <message> + <source>Version</source> + <translation>Version</translation> + </message> + <message> + <source>Starting Block</source> + <translation>Starting Block</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Synced Headers</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Synced Blocks</translation> + </message> + <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>The mapped Autonomous System used for diversifying peer selection.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapped AS</translation> + </message> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</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>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>Decrease font size</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Increase font size</translation> + </message> + <message> + <source>Services</source> + <translation>Services</translation> + </message> + <message> + <source>Connection Time</source> + <translation>Connection Time</translation> + </message> + <message> + <source>Last Send</source> + <translation>Last Send</translation> + </message> + <message> + <source>Last Receive</source> + <translation>Last Receive</translation> + </message> + <message> + <source>Ping Time</source> + <translation>Ping Time</translation> + </message> + <message> + <source>The duration of a currently outstanding ping.</source> + <translation>The duration of a currently outstanding ping.</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>Ping Wait</translation> + </message> + <message> + <source>Min Ping</source> + <translation>Min Ping</translation> + </message> + <message> + <source>Time Offset</source> + <translation>Time Offset</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>&Open</source> + <translation>&Open</translation> + </message> + <message> + <source>&Console</source> + <translation>&Console</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation>&Network Traffic</translation> + </message> + <message> + <source>Totals</source> + <translation>Totals</translation> + </message> + <message> + <source>In:</source> + <translation>In:</translation> + </message> + <message> + <source>Out:</source> + <translation>Out:</translation> + </message> + <message> + <source>Debug log file</source> + <translation>Debug log file</translation> + </message> + <message> + <source>Clear console</source> + <translation>Clear console</translation> + </message> + <message> + <source>1 &hour</source> + <translation>1 &hour</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &day</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &week</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &year</translation> + </message> + <message> + <source>&Disconnect</source> + <translation>&Disconnect</translation> + </message> + <message> + <source>Ban for</source> + <translation>Ban for</translation> + </message> + <message> + <source>&Unban</source> + <translation>&Unban</translation> + </message> + <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Welcome to the %1 RPC console.</translation> + </message> + <message> + <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> + <translation>Use up and down arrows to navigate history, and %1 to clear screen.</translation> + </message> + <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Type %1 for an overview of available commands.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>For more information on using this console type %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>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.</translation> + </message> + <message> + <source>Network activity disabled</source> + <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> + <message> + <source>via %1</source> + <translation>via %1</translation> + </message> + <message> + <source>never</source> + <translation>never</translation> + </message> + <message> + <source>Inbound</source> + <translation>Inbound</translation> + </message> + <message> + <source>Outbound</source> + <translation>Outbound</translation> + </message> + <message> + <source>Unknown</source> + <translation>Unknown</translation> + </message> +</context> +<context> + <name>ReceiveCoinsDialog</name> + <message> + <source>&Amount:</source> + <translation>&Amount:</translation> + </message> + <message> + <source>&Label:</source> + <translation>&Label:</translation> + </message> + <message> + <source>&Message:</source> + <translation>&Message:</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>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.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <translation>An optional label to associate with the new receiving address.</translation> + </message> + <message> + <source>Use this form to request payments. All fields are <b>optional</b>.</source> + <translation>Use this form to request payments. All fields are <b>optional</b>.</translation> + </message> + <message> + <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <translation>An optional amount to request. Leave this empty or zero to not request a specific amount.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>An optional message that is attached to the payment request and may be displayed to the sender.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Create new receiving address</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Clear all fields of the form.</translation> + </message> + <message> + <source>Clear</source> + <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> + <message> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation>Show the selected request (does the same as double clicking an entry)</translation> + </message> + <message> + <source>Show</source> + <translation>Show</translation> + </message> + <message> + <source>Remove the selected entries from the list</source> + <translation>Remove the selected entries from the list</translation> + </message> + <message> + <source>Remove</source> + <translation>Remove</translation> + </message> + <message> + <source>Copy URI</source> + <translation>Copy URI</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy message</source> + <translation>Copy message</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Non se puido desbloquear a carteira.</translation> + </message> + </context> +<context> + <name>ReceiveRequestDialog</name> + <message> + <source>Amount:</source> + <translation>Amount:</translation> + </message> + <message> + <source>Message:</source> + <translation>Message:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Carteira:</translation> + </message> + <message> + <source>Copy &URI</source> + <translation>Copy &URI</translation> + </message> + <message> + <source>Copy &Address</source> + <translation>Copy &Address</translation> + </message> + <message> + <source>&Save Image...</source> + <translation>&Save Image...</translation> + </message> + <message> + <source>Request payment to %1</source> + <translation>Request payment to %1</translation> + </message> + <message> + <source>Payment information</source> + <translation>Payment information</translation> + </message> +</context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>Message</source> + <translation>Message</translation> + </message> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> + <message> + <source>(no message)</source> + <translation>(no message)</translation> + </message> + <message> + <source>(no amount requested)</source> + <translation>(no amount requested)</translation> + </message> + <message> + <source>Requested</source> + <translation>Requested</translation> + </message> +</context> +<context> + <name>SendCoinsDialog</name> + <message> + <source>Send Coins</source> + <translation>Send Coins</translation> + </message> + <message> + <source>Coin Control Features</source> + <translation>Coin Control Features</translation> + </message> + <message> + <source>Inputs...</source> + <translation>Inputs...</translation> + </message> + <message> + <source>automatically selected</source> + <translation>automatically selected</translation> + </message> + <message> + <source>Insufficient funds!</source> + <translation>Insufficient funds!</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Quantity:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Amount:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Fee:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>After Fee:</translation> + </message> + <message> + <source>Change:</source> + <translation>Change:</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>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</translation> + </message> + <message> + <source>Custom change address</source> + <translation>Custom change address</translation> + </message> + <message> + <source>Transaction Fee:</source> + <translation>Transaction Fee:</translation> + </message> + <message> + <source>Choose...</source> + <translation>Choose...</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>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.</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>Warning: Fee estimation is currently not possible.</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> + <message> + <source>Hide</source> + <translation>Hide</translation> + </message> + <message> + <source>Recommended:</source> + <translation>Recommended:</translation> + </message> + <message> + <source>Custom:</source> + <translation>Custom:</translation> + </message> + <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(Smart fee not initialized yet. This usually takes a few blocks...)</translation> + </message> + <message> + <source>Send to multiple recipients at once</source> + <translation>Send to multiple recipients at once</translation> + </message> + <message> + <source>Add &Recipient</source> + <translation>Add &Recipient</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Clear all fields of the form.</translation> + </message> + <message> + <source>Dust:</source> + <translation>Dust:</translation> + </message> + <message> + <source>Hide transaction fee settings</source> + <translation>Hide transaction fee settings</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>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.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>A too low fee might result in a never confirming transaction (read the tooltip)</translation> + </message> + <message> + <source>Confirmation time target:</source> + <translation>Confirmation time target:</translation> + </message> + <message> + <source>Enable Replace-By-Fee</source> + <translation>Enable 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>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.</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> + <source>Balance:</source> + <translation>Balance:</translation> + </message> + <message> + <source>Confirm the send action</source> + <translation>Confirm the send action</translation> + </message> + <message> + <source>S&end</source> + <translation>S&end</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Copy quantity</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Copy fee</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Copy after fee</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Copy bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Copy dust</translation> + </message> + <message> + <source>Copy change</source> + <translation>Copy change</translation> + </message> + <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 blocks)</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation>Cr&eate Unsigned</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation> from wallet '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 to '%2'</translation> + </message> + <message> + <source>%1 to %2</source> + <translation>%1 to %2</translation> + </message> + <message> + <source>Do you want to draft this transaction?</source> + <translation>Do you want to draft this transaction?</translation> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation>Are you sure you want to send?</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> + </message> + <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</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> + <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Not signalling Replace-By-Fee, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>To review recipient list click "Show Details..."</source> + <translation>To review recipient list click "Show Details..."</translation> + </message> + <message> + <source>Confirm send coins</source> + <translation>Confirm send coins</translation> + </message> + <message> + <source>Confirm transaction proposal</source> + <translation>Confirm transaction proposal</translation> + </message> + <message> + <source>Send</source> + <translation>Send</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Watch-only balance:</translation> + </message> + <message> + <source>The recipient address is not valid. Please recheck.</source> + <translation>The recipient address is not valid. Please recheck.</translation> + </message> + <message> + <source>The amount to pay must be larger than 0.</source> + <translation>The amount to pay must be larger than 0.</translation> + </message> + <message> + <source>The amount exceeds your balance.</source> + <translation>The amount exceeds your balance.</translation> + </message> + <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation>The total exceeds your balance when the %1 transaction fee is included.</translation> + </message> + <message> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation>Duplicate address found: addresses should only be used once each.</translation> + </message> + <message> + <source>Transaction creation failed!</source> + <translation>Transaction creation failed!</translation> + </message> + <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>A fee higher than %1 is considered an absurdly high fee.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Payment request expired.</translation> + </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Estimated to begin confirmation within %n block.</numerusform><numerusform>Estimated to begin confirmation within %n blocks.</numerusform></translation> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Warning: Invalid Bitcoin address</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>Warning: Unknown change address</translation> + </message> + <message> + <source>Confirm custom change address</source> + <translation>Confirm custom change address</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>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?</translation> + </message> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> +</context> +<context> + <name>SendCoinsEntry</name> + <message> + <source>A&mount:</source> + <translation>A&mount:</translation> + </message> + <message> + <source>Pay &To:</source> + <translation>Pay &To:</translation> + </message> + <message> + <source>&Label:</source> + <translation>&Label:</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Choose previously used address</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>The Bitcoin address to send the payment to</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Remove this entry</source> + <translation>Remove this entry</translation> + </message> + <message> + <source>The amount to send in the selected unit</source> + <translation>The amount to send in the selected unit</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>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.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation>S&ubtract fee from amount</translation> + </message> + <message> + <source>Use available balance</source> + <translation>Use available balance</translation> + </message> + <message> + <source>Message:</source> + <translation>Message:</translation> + </message> + <message> + <source>This is an unauthenticated payment request.</source> + <translation>This is an unauthenticated payment request.</translation> + </message> + <message> + <source>This is an authenticated payment request.</source> + <translation>This is an authenticated payment request.</translation> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation>Enter a label for this address to add it to the list of used addresses</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>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.</translation> + </message> + <message> + <source>Pay To:</source> + <translation>Pay To:</translation> + </message> + <message> + <source>Memo:</source> + <translation>Memo:</translation> + </message> +</context> +<context> + <name>ShutdownWindow</name> + <message> + <source>%1 is shutting down...</source> + <translation>%1 is shutting down...</translation> + </message> + <message> + <source>Do not shut down the computer until this window disappears.</source> + <translation>Do not shut down the computer until this window disappears.</translation> + </message> +</context> +<context> + <name>SignVerifyMessageDialog</name> + <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Signatures - Sign / Verify a Message</translation> + </message> + <message> + <source>&Sign Message</source> + <translation>&Sign Message</translation> + </message> + <message> + <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <translation>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.</translation> + </message> + <message> + <source>The Bitcoin address to sign the message with</source> + <translation>The Bitcoin address to sign the message with</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Choose previously used address</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Enter the message you want to sign here</source> + <translation>Enter the message you want to sign here</translation> + </message> + <message> + <source>Signature</source> + <translation>Signature</translation> + </message> + <message> + <source>Copy the current signature to the system clipboard</source> + <translation>Copy the current signature to the system clipboard</translation> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation>Sign the message to prove you own this Bitcoin address</translation> + </message> + <message> + <source>Sign &Message</source> + <translation>Sign &Message</translation> + </message> + <message> + <source>Reset all sign message fields</source> + <translation>Reset all sign message fields</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> + <source>&Verify Message</source> + <translation>&Verify Message</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>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!</translation> + </message> + <message> + <source>The Bitcoin address the message was signed with</source> + <translation>The Bitcoin address the message was signed with</translation> + </message> + <message> + <source>The signed message to verify</source> + <translation>The signed message to verify</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>The signature given when the message was signed</translation> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation>Verify the message to ensure it was signed with the specified Bitcoin address</translation> + </message> + <message> + <source>Verify &Message</source> + <translation>Verify &Message</translation> + </message> + <message> + <source>Reset all verify message fields</source> + <translation>Reset all verify message fields</translation> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation>Click "Sign Message" to generate signature</translation> + </message> + <message> + <source>The entered address is invalid.</source> + <translation>The entered address is invalid.</translation> + </message> + <message> + <source>Please check the address and try again.</source> + <translation>Please check the address and try again.</translation> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation>The entered address does not refer to a key.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation>Wallet unlock was cancelled.</translation> + </message> + <message> + <source>No error</source> + <translation>No error</translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation>Private key for the entered address is not available.</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Message signing failed.</translation> + </message> + <message> + <source>Message signed.</source> + <translation>Message signed.</translation> + </message> + <message> + <source>The signature could not be decoded.</source> + <translation>The signature could not be decoded.</translation> + </message> + <message> + <source>Please check the signature and try again.</source> + <translation>Please check the signature and try again.</translation> + </message> + <message> + <source>The signature did not match the message digest.</source> + <translation>The signature did not match the message digest.</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>Message verification failed.</translation> + </message> + <message> + <source>Message verified.</source> + <translation>Message verified.</translation> + </message> +</context> +<context> + <name>TrafficGraphWidget</name> + <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>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> + <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>conflicted with a transaction with %1 confirmations</source> + <translation>conflicted with a transaction with %1 confirmations</translation> + </message> + <message> + <source>0/unconfirmed, %1</source> + <translation>0/unconfirmed, %1</translation> + </message> + <message> + <source>in memory pool</source> + <translation>in memory pool</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>not in memory pool</translation> + </message> + <message> + <source>abandoned</source> + <translation>abandoned</translation> + </message> + <message> + <source>%1/unconfirmed</source> + <translation>%1/unconfirmed</translation> + </message> + <message> + <source>%1 confirmations</source> + <translation>%1 confirmations</translation> + </message> + <message> + <source>Status</source> + <translation>Status</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Source</source> + <translation>Source</translation> + </message> + <message> + <source>Generated</source> + <translation>Generated</translation> + </message> + <message> + <source>From</source> + <translation>From</translation> + </message> + <message> + <source>unknown</source> + <translation>unknown</translation> + </message> + <message> + <source>To</source> + <translation>To</translation> + </message> + <message> + <source>own address</source> + <translation>own address</translation> + </message> + <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> + <source>label</source> + <translation>label</translation> + </message> + <message> + <source>Credit</source> + <translation>Credit</translation> + </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>matures in %n more block</numerusform><numerusform>matures in %n more blocks</numerusform></translation> + </message> + <message> + <source>not accepted</source> + <translation>not accepted</translation> + </message> + <message> + <source>Debit</source> + <translation>Debit</translation> + </message> + <message> + <source>Total debit</source> + <translation>Total debit</translation> + </message> + <message> + <source>Total credit</source> + <translation>Total credit</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>Transaction fee</translation> + </message> + <message> + <source>Net amount</source> + <translation>Net amount</translation> + </message> + <message> + <source>Message</source> + <translation>Message</translation> + </message> + <message> + <source>Comment</source> + <translation>Comment</translation> + </message> + <message> + <source>Transaction ID</source> + <translation>Transaction ID</translation> + </message> + <message> + <source>Transaction total size</source> + <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> + <message> + <source> (Certificate was not verified)</source> + <translation> (Certificate was not verified)</translation> + </message> + <message> + <source>Merchant</source> + <translation>Merchant</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>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.</translation> + </message> + <message> + <source>Debug information</source> + <translation>Debug information</translation> + </message> + <message> + <source>Transaction</source> + <translation>Transaction</translation> + </message> + <message> + <source>Inputs</source> + <translation>Inputs</translation> + </message> + <message> + <source>Amount</source> + <translation>Amount</translation> + </message> + <message> + <source>true</source> + <translation>true</translation> + </message> + <message> + <source>false</source> + <translation>false</translation> + </message> +</context> +<context> + <name>TransactionDescDialog</name> + <message> + <source>This pane shows a detailed description of the transaction</source> + <translation>This pane shows a detailed description of the transaction</translation> + </message> + <message> + <source>Details for %1</source> + <translation>Details for %1</translation> + </message> +</context> +<context> + <name>TransactionTableModel</name> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Type</source> + <translation>Type</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Open for %n more block</numerusform><numerusform>Open for %n more blocks</numerusform></translation> + </message> + <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>Unconfirmed</source> + <translation>Unconfirmed</translation> + </message> + <message> + <source>Abandoned</source> + <translation>Abandoned</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation>Confirming (%1 of %2 recommended confirmations)</translation> + </message> + <message> + <source>Confirmed (%1 confirmations)</source> + <translation>Confirmed (%1 confirmations)</translation> + </message> + <message> + <source>Conflicted</source> + <translation>Conflicted</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation>Immature (%1 confirmations, will be available after %2)</translation> + </message> + <message> + <source>Generated but not accepted</source> + <translation>Generated but not accepted</translation> + </message> + <message> + <source>Received with</source> + <translation>Received with</translation> + </message> + <message> + <source>Received from</source> + <translation>Received from</translation> + </message> + <message> + <source>Sent to</source> + <translation>Sent to</translation> + </message> + <message> + <source>Payment to yourself</source> + <translation>Payment to yourself</translation> + </message> + <message> + <source>Mined</source> + <translation>Mined</translation> + </message> + <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> + <source>(n/a)</source> + <translation>(n/a)</translation> + </message> + <message> + <source>(no label)</source> + <translation>(no label)</translation> + </message> + <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation>Transaction status. Hover over this field to show number of confirmations.</translation> + </message> + <message> + <source>Date and time that the transaction was received.</source> + <translation>Date and time that the transaction was received.</translation> + </message> + <message> + <source>Type of transaction.</source> + <translation>Type of transaction.</translation> + </message> + <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Whether or not a watch-only address is involved in this transaction.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>User-defined intent/purpose of the transaction.</translation> + </message> + <message> + <source>Amount removed from or added to balance.</source> + <translation>Amount removed from or added to balance.</translation> + </message> +</context> +<context> + <name>TransactionView</name> + <message> + <source>All</source> + <translation>All</translation> + </message> + <message> + <source>Today</source> + <translation>Today</translation> + </message> + <message> + <source>This week</source> + <translation>This week</translation> + </message> + <message> + <source>This month</source> + <translation>This month</translation> + </message> + <message> + <source>Last month</source> + <translation>Last month</translation> + </message> + <message> + <source>This year</source> + <translation>This year</translation> + </message> + <message> + <source>Range...</source> + <translation>Range...</translation> + </message> + <message> + <source>Received with</source> + <translation>Received with</translation> + </message> + <message> + <source>Sent to</source> + <translation>Sent to</translation> + </message> + <message> + <source>To yourself</source> + <translation>To yourself</translation> + </message> + <message> + <source>Mined</source> + <translation>Mined</translation> + </message> + <message> + <source>Other</source> + <translation>Other</translation> + </message> + <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Enter address, transaction id, or label to search</translation> + </message> + <message> + <source>Min amount</source> + <translation>Min amount</translation> + </message> + <message> + <source>Abandon transaction</source> + <translation>Abandon transaction</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>Increase transaction fee</translation> + </message> + <message> + <source>Copy address</source> + <translation>Copy address</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Copy transaction ID</translation> + </message> + <message> + <source>Copy raw transaction</source> + <translation>Copy raw transaction</translation> + </message> + <message> + <source>Copy full transaction details</source> + <translation>Copy full transaction details</translation> + </message> + <message> + <source>Edit label</source> + <translation>Edit label</translation> + </message> + <message> + <source>Show transaction details</source> + <translation>Show transaction details</translation> + </message> + <message> + <source>Export Transaction History</source> + <translation>Export Transaction History</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Comma separated file (*.csv)</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Confirmed</translation> + </message> + <message> + <source>Watch-only</source> + <translation>Watch-only</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Type</source> + <translation>Type</translation> + </message> + <message> + <source>Label</source> + <translation>Label</translation> + </message> + <message> + <source>Address</source> + <translation>Address</translation> + </message> + <message> + <source>ID</source> + <translation>ID</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Exporting Failed</translation> + </message> + <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation>There was an error trying to save the transaction history to %1.</translation> + </message> + <message> + <source>Exporting Successful</source> + <translation>Exporting Successful</translation> + </message> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>The transaction history was successfully saved to %1.</translation> + </message> + <message> + <source>Range:</source> + <translation>Range:</translation> + </message> + <message> + <source>to</source> + <translation>to</translation> + </message> +</context> +<context> + <name>UnitDisplayStatusBarControl</name> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Unit to show amounts in. Click to select another unit.</translation> + </message> +</context> +<context> + <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>Close wallet</translation> + </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Are you sure you wish to close the wallet <i>%1</i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</translation> + </message> + </context> +<context> + <name>WalletFrame</name> + <message> + <source>Create a new wallet</source> + <translation>Crear unha nova carteira</translation> + </message> +</context> +<context> + <name>WalletModel</name> + <message> + <source>Send Coins</source> + <translation>Send Coins</translation> + </message> + <message> + <source>Fee bump error</source> + <translation>Fee bump error</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation>Increasing transaction fee failed</translation> + </message> + <message> + <source>Do you want to increase the fee?</source> + <translation>Do you want to increase the fee?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Do you want to draft a transaction with fee increase?</translation> + </message> + <message> + <source>Current fee:</source> + <translation>Current fee:</translation> + </message> + <message> + <source>Increase:</source> + <translation>Increase:</translation> + </message> + <message> + <source>New fee:</source> + <translation>New fee:</translation> + </message> + <message> + <source>Confirm fee bump</source> + <translation>Confirm fee bump</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Can't draft transaction.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT copied</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Can't sign transaction.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Could not commit transaction</translation> + </message> + <message> + <source>default wallet</source> + <translation>default wallet</translation> + </message> +</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>Export the data in the current tab to a file</translation> + </message> + <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>Backup Wallet</translation> + </message> + <message> + <source>Wallet Data (*.dat)</source> + <translation>Wallet Data (*.dat)</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>Backup Failed</translation> + </message> + <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation>There was an error trying to save the wallet data to %1.</translation> + </message> + <message> + <source>Backup Successful</source> + <translation>Backup Successful</translation> + </message> + <message> + <source>The wallet data was successfully saved to %1.</source> + <translation>The wallet data was successfully saved to %1.</translation> + </message> + <message> + <source>Cancel</source> + <translation>Cancel</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>Distributed under the MIT software license, see the accompanying file %s or %s</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Prune configured below the minimum of %d MiB. Please use a higher number.</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>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Pruning blockstore...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Unable to start HTTP server. See debug log for details.</translation> + </message> + <message> + <source>The %s developers</source> + <translation>The %s developers</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Cannot obtain a lock on data directory %s. %s is probably already running.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Cannot provide specific connections and have addrman find outgoing connections at the same.</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>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</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> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Please contribute if you find %s useful. Visit %s for further information about the software.</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>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</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>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation> + </message> + <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>This is the transaction fee you may discard if change is smaller than dust at this level</translation> + </message> + <message> + <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <translation>Unable to replay blocks. You will need to rebuild the database using -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>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</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>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation> + </message> + <message> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool must be at least %d MB</translation> + </message> + <message> + <source>Cannot resolve -%s address: '%s'</source> + <translation>Cannot resolve -%s address: '%s'</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>Change index out of range</translation> + </message> + <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Config setting for %s only applied on %s network when in [%s] section.</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation>Corrupted block database detected</translation> + </message> + <message> + <source>Could not find asmap file %s</source> + <translation>Could not find asmap file %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Could not parse asmap file %s</translation> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation>Do you want to rebuild the block database now?</translation> + </message> + <message> + <source>Error initializing block database</source> + <translation>Error initializing block database</translation> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation>Error initializing wallet database environment %s!</translation> + </message> + <message> + <source>Error loading %s</source> + <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> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Error loading %s: Wallet requires newer version of %s</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>Error loading block database</translation> + </message> + <message> + <source>Error opening block database</source> + <translation>Error opening block database</translation> + </message> + <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> + </message> + <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Failed to rescan the wallet during initialization</translation> + </message> + <message> + <source>Importing...</source> + <translation>Importing...</translation> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>Initialization sanity check failed. %s is shutting down.</translation> + </message> + <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Invalid P2P permission: '%s'</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Invalid amount for -%s=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -discardfee=<amount>: '%s'</source> + <translation>Invalid amount for -discardfee=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> + <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>Unknown address type '%s'</source> + <translation>Unknown address type '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Unknown change type '%s'</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> + <message> + <source>Loading banlist...</source> + <translation>Loading banlist...</translation> + </message> + <message> + <source>Not enough file descriptors available.</source> + <translation>Not enough file descriptors available.</translation> + </message> + <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Prune cannot be configured with a negative value.</translation> + </message> + <message> + <source>Prune mode is incompatible with -txindex.</source> + <translation>Prune mode is incompatible with -txindex.</translation> + </message> + <message> + <source>Replaying blocks...</source> + <translation>Replaying blocks...</translation> + </message> + <message> + <source>Rewinding blocks...</source> + <translation>Rewinding blocks...</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>The source code is available from %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <translation>Transaction fee and change calculation failed</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <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 logging category %s=%s.</source> + <translation>Unsupported logging category %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Upgrading UTXO database</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>User Agent comment (%s) contains unsafe characters.</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>Verifying blocks...</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Wallet needed to be rewritten: restart %s to complete</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Error: Listening for incoming connections failed (listen returned error %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>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>The transaction amount is too small to send after the fee has been deducted</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>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Error reading from database, shutting down.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Error upgrading chainstate database</translation> + </message> + <message> + <source>Error: Disk space is low for %s</source> + <translation>Error: Disk space is low for %s</translation> + </message> + <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Invalid -onion address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Invalid -proxy address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Invalid netmask specified in -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Need to specify a port with -whitebind: '%s'</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Prune mode is incompatible with -blockfilterindex.</translation> + </message> + <message> + <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> + <translation>Reducing -maxconnections from %d to %d, because of system limitations.</translation> + </message> + <message> + <source>Section [%s] is not recognized.</source> + <translation>Section [%s] is not recognized.</translation> + </message> + <message> + <source>Signing transaction failed</source> + <translation>Signing transaction failed</translation> + </message> + <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Specified -walletdir "%s" does not exist</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Specified -walletdir "%s" is a relative path</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Specified -walletdir "%s" is not a directory</translation> + </message> + <message> + <source>The specified config file %s does not exist +</source> + <translation>The specified config file %s does not exist +</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>The transaction amount is too small to pay the fee</translation> + </message> + <message> + <source>This is experimental software.</source> + <translation>This is experimental software.</translation> + </message> + <message> + <source>Transaction amount too small</source> + <translation>Transaction amount too small</translation> + </message> + <message> + <source>Transaction too large</source> + <translation>Transaction too large</translation> + </message> + <message> + <source>Unable to bind to %s on this computer (bind returned error %s)</source> + <translation>Unable to bind to %s on this computer (bind returned error %s)</translation> + </message> + <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>Unable to create the PID file '%s': %s</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>Unable to generate initial keys</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Unknown -blockfilterindex value %s.</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>Verifying wallet(s)...</translation> + </message> + <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Warning: unknown new rules activated (versionbit %i)</translation> + </message> + <message> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation> + </message> + <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>This is the transaction fee you may pay when fee estimates are not available.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s is set very high!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Error loading wallet %s. Duplicate -wallet filename specified.</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>Starting network threads...</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>The wallet will avoid paying less than the minimum relay fee.</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>This is the minimum transaction fee you pay on every transaction.</translation> + </message> + <message> + <source>This is the transaction fee you will pay if you send a transaction.</source> + <translation>This is the transaction fee you will pay if you send a transaction.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <translation>Transaction amounts must not be negative</translation> + </message> + <message> + <source>Transaction has too long of a mempool chain</source> + <translation>Transaction has too long of a mempool chain</translation> + </message> + <message> + <source>Transaction must have at least one recipient</source> + <translation>Transaction must have at least one recipient</translation> + </message> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation>Unknown network specified in -onlynet: '%s'</translation> + </message> + <message> + <source>Insufficient funds</source> + <translation>Insufficient funds</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> + <message> + <source>Loading wallet...</source> + <translation>Loading wallet...</translation> + </message> + <message> + <source>Cannot downgrade wallet</source> + <translation>Cannot downgrade wallet</translation> + </message> + <message> + <source>Rescanning...</source> + <translation>Rescanning...</translation> + </message> + <message> + <source>Done loading</source> + <translation>Done loading</translation> + </message> +</context> +</TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts index 78570e8bbf..bd64fdd179 100644 --- a/src/qt/locale/bitcoin_he.ts +++ b/src/qt/locale/bitcoin_he.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,23 +15,23 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>העתק את הכתובת המסומנת ללוח העריכה</translation> + <translation>העתקת את הכתובת המסומנת ללוח</translation> </message> <message> <source>&Copy</source> - <translation>&העתק</translation> + <translation>&העתקה</translation> </message> <message> <source>C&lose</source> - <translation>&סגור</translation> + <translation>&סגירה</translation> </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> @@ -43,15 +43,15 @@ </message> <message> <source>&Delete</source> - <translation>&מחק</translation> + <translation>&מחיקה</translation> </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> @@ -70,12 +70,14 @@ <translation>אלו הן כתובות הביטקוין שלך לשליחת תשלומים. חשוב לבדוק את הסכום ואת הכתובת המקבלת לפני שליחת מטבעות.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>אלה כתובות הביטקוין שלך לקבלת תשלומים. השתמש בלחצן 'צור כתובת קבלה חדשה' בכרטיסייה קבלה כדי ליצור כתובות חדשות.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>אלו כתובת ביטקוין שלך לקבלת תשלומים. ניתן להשתמש בכפתור 'יצירת כתובת קבלה חדשה' בלשונית הקבלה ליצירת כתובות חדשות. +חתימה אפשרית רק עבור כתובות מסוג 'legacy'.</translation> </message> <message> <source>&Copy Address</source> - <translation>&העתק כתובת</translation> + <translation>&העתקת כתובת</translation> </message> <message> <source>Copy &Label</source> @@ -121,11 +123,11 @@ <name>AskPassphraseDialog</name> <message> <source>Passphrase Dialog</source> - <translation>שיח סיסמא</translation> + <translation>תיבת דו־שיח סיסמה</translation> </message> <message> <source>Enter passphrase</source> - <translation>הכנס סיסמה</translation> + <translation>יש להזין סיסמה</translation> </message> <message> <source>New passphrase</source> @@ -137,11 +139,11 @@ </message> <message> <source>Show passphrase</source> - <translation>הצג סיסמה</translation> + <translation>הצגת סיסמה</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> @@ -180,6 +182,31 @@ <translation>הארנק מוצפן</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>הקש סיסמה חדשה לארנק. +השתמש בסיסמה הכוללת עשרה או יותר תווים אקראים, או שמונה או יותר מילים.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>הקש את הסיסמא הישנה והחדשה לארנק.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>זכור שהצפנת הארנק לא יכולה להגן עליך לגמרי מגניבת המטבעות שלך על ידי תוכנה זדונית שנמצאת על המחשב שלך.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>הארנק המיועד להצפנה</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>הארנק שלך עומד להיות מוצפן.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>הארנק שלך מוצפן כעת.</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> @@ -259,7 +286,7 @@ </message> <message> <source>Quit application</source> - <translation>סגור תוכנה</translation> + <translation>יציאה מהיישום</translation> </message> <message> <source>&About %1</source> @@ -279,7 +306,7 @@ </message> <message> <source>&Options...</source> - <translation>&אפשרויות…</translation> + <translation>&אפשרויות...</translation> </message> <message> <source>Modify configuration options for %1</source> @@ -287,11 +314,11 @@ </message> <message> <source>&Encrypt Wallet...</source> - <translation>&הצפנת הארנק…</translation> + <translation>&הצפנת הארנק...</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>&גיבוי הארנק…</translation> + <translation>&גיבוי הארנק...</translation> </message> <message> <source>&Change Passphrase...</source> @@ -299,7 +326,15 @@ </message> <message> <source>Open &URI...</source> - <translation>פתיחת &כתובת משאב…</translation> + <translation>פתיחת &כתובת משאב...</translation> + </message> + <message> + <source>Create Wallet...</source> + <translation>יצירת ארנק...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>יצירת ארנק חדש</translation> </message> <message> <source>Wallet:</source> @@ -339,7 +374,7 @@ </message> <message> <source>Change the passphrase used for wallet encryption</source> - <translation>שנה את הסיסמא המשמשת להצפנת הארנק</translation> + <translation>שינוי הסיסמה המשמשת להצפנת הארנק</translation> </message> <message> <source>&Verify message...</source> @@ -431,7 +466,7 @@ </message> <message> <source>Transactions after this will not yet be visible.</source> - <translation>ההעברות שבוצעו לאחר העברה זו לא יופיעו.</translation> + <translation>עסקאות שבוצעו לאחר העברה זו לא יופיעו.</translation> </message> <message> <source>Error</source> @@ -450,6 +485,30 @@ <translation>עדכני</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&העלה PSBT מקובץ...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>העלה עיסקת ביטקוין חתומה חלקית</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>טעינת PSBT מלוח הגזירים...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>טעינת עסקת ביטקוין חתומה חלקית מלוח הגזירים</translation> + </message> + <message> + <source>Node window</source> + <translation>חלון צומת</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>פתיחת ניפוי באגים בצומת וגם מסוף בקרה לאבחון</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&כתובות למשלוח</translation> </message> @@ -458,6 +517,10 @@ <translation>&כתובות לקבלה</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>פתיחת ביטקוין: כתובת משאב</translation> + </message> + <message> <source>Open Wallet</source> <translation>פתיחת ארנק</translation> </message> @@ -474,10 +537,27 @@ <translation>סגירת ארנק</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>סגירת כל הארנקים...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>סגירת כל הארנקים</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>יש להציג את הודעת העזרה של %1 כדי להציג רשימה עם אפשרויות שורת פקודה לביטקוין</translation> </message> <message> + <source>&Mask values</source> + <translation>&הסוואת ערכים</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>הסווה את הערכים בלשונית התיאור הכללי +</translation> + </message> + <message> <source>default wallet</source> <translation>ארנק בררת מחדל</translation> </message> @@ -526,7 +606,7 @@ <message> <source>Amount: %1 </source> - <translation>כמות: %1 + <translation>סכום: %1 </translation> </message> <message> @@ -582,8 +662,12 @@ <translation>הארנק <b>מוצפן</b> ו<b>נעול</b> כרגע</translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>אירעה שגיאה חמורה. אין אפשרות להשתמש עוד בביטקוין באופן מאובטח והיישום ייסגר.</translation> + <source>Original message:</source> + <translation>הודעה מקורית:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>אירעה שגיאה חמורה, %1 לא יכול להמשיך בבטחון ולכן יופסק.</translation> </message> </context> <context> @@ -634,7 +718,7 @@ </message> <message> <source>Amount</source> - <translation>כמות</translation> + <translation>סכום</translation> </message> <message> <source>Received with label</source> @@ -670,7 +754,7 @@ </message> <message> <source>Copy transaction ID</source> - <translation>העתקת מזהה ההעברה</translation> + <translation>העתקת מזהה העסקה</translation> </message> <message> <source>Lock unspent</source> @@ -739,10 +823,62 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Create wallet failed</source> + <translation>יצירת הארנק נכשלה</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>אזהרה לגבי יצירת הארנק</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>יצירת ארנק</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>שם הארנק</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>הצפן את הארנק. הארנק יהיה מוצפן באמצעות סיסמא לבחירתך.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>הצפנת ארנק</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>נטרלו מפתחות פרטיים לארנק זה. ארנקים עם מפתחות פרטיים מנוטרלים יהיו מחוסרי מפתחות פרטיים וללא מקור HD או מפתחות מיובאים. זהו אידאלי לארנקי צפייה בלבד.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>השבתת מפתחות פרטיים</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>הכינו ארנק ריק. ארנקים ריקים הנם ללא מפתחות פרטיים ראשוניים או סקריפטים. מפתחות פרטיים או כתובות ניתנים לייבוא, או שניתן להגדיר מקור HD במועד מאוחר יותר. </translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>צור ארנק ריק</translation> + </message> + <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>השתמש ב descriptors לניהול scriptPubKey </translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>ארנק Descriptor </translation> + </message> + <message> + <source>Create</source> + <translation>יצירה</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -814,7 +950,7 @@ </message> <message> <source>Path already exists, and is not a directory.</source> - <translation>הנתיב כבר קיים ואינו מצביע על תיקייה.</translation> + <translation>הנתיב כבר קיים ואינו מצביע על תיקיה.</translation> </message> <message> <source>Cannot create data directory here.</source> @@ -855,6 +991,10 @@ <translation>בעת לחיצה על אישור, %1 יחל בהורדה ועיבוד מלאים של שרשרת המקטעים %4 (%2 ג״ב) החל מההעברות הראשונות ב־%3 עם ההשקה הראשונית של %4.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>חזרה לאחור מהגדרות אלו מחייב הורדה מחדש של כל שרשרת הבלוקים. מהיר יותר להוריד את השרשרת המלאה ולקטום אותה מאוחר יותר. הדבר מנטרל כמה תכונות מתקדמות.</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>הסינכרון הראשוני הוא תובעני ועלול לחשוף בעיות חומרה במחשב שהיו חבויות עד כה. כל פעם שתריץ %1 התהליך ימשיך בהורדה מהנקודה שבה הוא עצר לאחרונה.</translation> </message> @@ -864,7 +1004,7 @@ </message> <message> <source>Use the default data directory</source> - <translation>שימוש בבררת המחדל של תיקיית הנתונים.</translation> + <translation>שימוש בתיקיית ברירת־המחדל</translation> </message> <message> <source>Use a custom data directory:</source> @@ -875,8 +1015,12 @@ <translation>ביטקוין</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>התעלם בלוקים לאחר ווריפיקציה, למעט %1 GB המאוחרים ביותר (המקוצצים)</translation> + </message> + <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> - <translation>מידע בנפח של לפחות %1 ג׳יגה-בייט יאוחסן בתיקייה זו, והוא יגדל עם הזמן.</translation> + <translation>לפחות %1 ג״ב של נתונים יאוחסנו בתיקייה זו, והם יגדלו עם הזמן.</translation> </message> <message> <source>Approximately %1 GB of data will be stored in this directory.</source> @@ -954,6 +1098,14 @@ <translation>הסתר</translation> </message> <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 מסתנכנים כרגע. תתבצע הורדת כותרות ובלוקים מעמיתים תוך אימותם עד הגעה לראש שרשרת הבלוקים .</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>לא ידוע. סינכרון כותרות (%1, %2%)...</translation> </message> @@ -961,6 +1113,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>פתיחת כתובת משאב ביטקוין</translation> + </message> + <message> <source>URI:</source> <translation>כתובת משאב:</translation> </message> @@ -968,6 +1124,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>פתיחת ארנק נכשלה</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>אזהרת פתיחת ארנק</translation> + </message> + <message> <source>default wallet</source> <translation>ארנק בררת מחדל</translation> </message> @@ -1004,17 +1168,13 @@ </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> - <translation>כתובת ה־IP של המתווך (לדוגמה IPv4: 127.0.0.1 / IPv6: ::1)</translation> + <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> @@ -1120,7 +1280,7 @@ </message> <message> <source>Proxy &IP:</source> - <translation>כתובת ה־IP של המ&תווך:</translation> + <translation>כתובת ה־&IP של הפרוקסי:</translation> </message> <message> <source>&Port:</source> @@ -1128,7 +1288,7 @@ </message> <message> <source>Port of the proxy (e.g. 9050)</source> - <translation>הפתחה של המתווך (למשל 9050)</translation> + <translation>הפתחה של הפרוקסי (למשל 9050)</translation> </message> <message> <source>Used for reaching peers via:</source> @@ -1147,10 +1307,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>התחברות לרשת ביטקוין דרך מתווך SOCKS5 נפרד לשירותי Tor נסתרים.</translation> - </message> - <message> <source>&Window</source> <translation>&חלון</translation> </message> @@ -1180,7 +1336,7 @@ </message> <message> <source>&Unit to show amounts in:</source> - <translation>י&חידת מידה להצגת כמויות:</translation> + <translation>י&חידת מידה להצגת סכומים:</translation> </message> <message> <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> @@ -1191,6 +1347,14 @@ <translation>האם להציג תכונות שליטת מטבע או לא.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>התחבר לרשת ביטקוין דרך פרוקסי נפרד SOCKS5 proxy לשרותי שכבות בצל (onion services).</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>השתמש בפרוקסי נפרד SOCKS&5 להגעה לעמיתים דרך שרותי השכבות של Tor :</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&כתובות אינטרנט של עסקאות צד שלישי</translation> </message> @@ -1307,7 +1471,7 @@ </message> <message> <source>Spendable:</source> - <translation>ניתנים לבזבוז</translation> + <translation>ניתנים לבזבוז:</translation> </message> <message> <source>Recent transactions</source> @@ -1325,6 +1489,133 @@ <source>Current total balance in watch-only addresses</source> <translation>המאזן הכולל הנוכחי בכתובות לצפייה בלבד</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>מצב הפרטיות הופעל עבור לשונית התאור הכללי. כדי להסיר את הסוואת הערכים, בטל את ההגדרות, ->הסוואת ערכים.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>שיח</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>חתימת עיסקה</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>שידור עיסקה</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>העתקה ללוח הגזירים</translation> + </message> + <message> + <source>Save...</source> + <translation>שמירה...</translation> + </message> + <message> + <source>Close</source> + <translation>סגירה</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>כשלון בטעינת העיסקה: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>כשלון בחתימת העיסקה: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>לא ניתן לחתום קלטים נוספים.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>נחתם קלט %1 אך יש צורך בחתימות נוספות.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>העיסקה נחתמה בהצלחה. העיסקה מוכנה לשידור.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>שגיאה לא מוכרת בעת עיבוד העיסקה.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>העיסקה שודרה בהצלחה! מזהה העיסקה: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>שידור העיסקה נכשל: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT הועתקה ללוח הגזירים.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>שמירת נתוני העיסקה</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>עיסקה חתומה חלקית (בינארי) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT נשמרה לדיסק.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation> * שליחת %1 אל %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>לא מצליח לחשב עמלת עיסקה או הערך הכולל של העיסקה.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>תשלום עמלת עיסקה:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>סכום כולל</translation> + </message> + <message> + <source>or</source> + <translation>או</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>לעיסקה יש %1 קלטים לא חתומים.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>לעיסקה חסר חלק מהמידע לגבי הקלטים.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>העיסקה עדיין נזקקת לחתימה(ות).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(אבל ארנק זה לא יכול לחתום על עיסקות.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(אבל לארנק הזה אין את המפתחות המתאימים.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>העיסקה חתומה במלואה ומוכנה לשידור.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>סטטוס העיסקה אינו ידוע.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1345,6 +1636,18 @@ <translation>'//:bitcoin' אינה כתובת URI תקינה. השתמשו במקום ב ':bitcoin'.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>אין אפשרות לעבד את בקשת התשלום כיון ש BIP70 אינו נתמך.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>עקב תקלות בטיחות רבות ב BIP70 מומלץ בחום להתעלם מההוראות של סוחר להחליף ארנקים </translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Iאם קיבלת הודעת שגיאה זו עליך לבקש מבעל העסק לספק URI תואם BIP21 URI.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>כתובת תשלום שגויה %1</translation> </message> @@ -1354,7 +1657,7 @@ </message> <message> <source>Payment request file handling</source> - <translation>טיפול בקבצי בקשות תשלום</translation> + <translation>טיפול בקובצי בקשות תשלום</translation> </message> </context> <context> @@ -1388,7 +1691,7 @@ <name>QObject</name> <message> <source>Amount</source> - <translation>כמות</translation> + <translation>סכום</translation> </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> @@ -1479,6 +1782,10 @@ <translation>שגיאה: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>שגיאה בהגדרות הראשוניות: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>הסגירה של %1 לא הושלמה בהצלחה עדיין…</translation> </message> @@ -1506,6 +1813,10 @@ <translation>שגיאה בקידוד ה URI לברקוד.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>תמיכה בקוד QR לא זמינה.</translation> + </message> + <message> <source>Save QR Code</source> <translation>שמירת קוד QR</translation> </message> @@ -1542,7 +1853,7 @@ </message> <message> <source>To specify a non-default location of the data directory use the '%1' option.</source> - <translation>כדי לשנות את מיקום תיקית הנתונים יש להשתמש באופצית '%1' .</translation> + <translation>כדי לציין מיקום שאינו ברירת המחדל לתיקיית הבלוקים יש להשתמש באפשרות "%1"</translation> </message> <message> <source>Blocksdir</source> @@ -1550,7 +1861,7 @@ </message> <message> <source>To specify a non-default location of the blocks directory use the '%1' option.</source> - <translation>כדי לשנות את מיקום תיקית הבלוקים יש להשתמש באופצית '%1' .</translation> + <translation>כדי לציין מיקום שאינו ברירת המחדל לתיקיית הבלוקים יש להשתמש באפשרות "%1"</translation> </message> <message> <source>Startup time</source> @@ -1573,10 +1884,6 @@ <translation>שרשרת מקטעים</translation> </message> <message> - <source>Current number of blocks</source> - <translation>מספר המקטעים הנוכחי</translation> - </message> - <message> <source>Memory Pool</source> <translation>מאגר זכרון</translation> </message> @@ -1621,10 +1928,6 @@ <translation>נא לבחור בעמית כדי להציג מידע מפורט.</translation> </message> <message> - <source>Whitelisted</source> - <translation>ברשימה הלבנה</translation> - </message> - <message> <source>Direction</source> <translation>כיוון</translation> </message> @@ -1645,12 +1948,28 @@ <translation>בלוקים מסונכרנים</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>המערכת האוטונומית הממופה משמשת לגיוון בחירת עמיתים.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>מופה בתור</translation> + </message> + <message> <source>User Agent</source> <translation>סוכן משתמש</translation> </message> <message> + <source>Node window</source> + <translation>חלון צומת</translation> + </message> + <message> + <source>Current block height</source> + <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> + <translation>פתיחת יומן ניפוי הבאגים %1 מתיקיית הנתונים הנוכחית. עבור קובצי יומן גדולים ייתכן זמן המתנה של מספר שניות.</translation> </message> <message> <source>Decrease font size</source> @@ -1661,12 +1980,12 @@ <translation>הגדל גודל גופן</translation> </message> <message> - <source>Services</source> - <translation>שירותים</translation> + <source>Permissions</source> + <translation>הרשאות</translation> </message> <message> - <source>Ban Score</source> - <translation>דירוג חסימה</translation> + <source>Services</source> + <translation>שירותים</translation> </message> <message> <source>Connection Time</source> @@ -1798,7 +2117,7 @@ </message> <message> <source>(node id: %1)</source> - <translation>(node id: %1)</translation> + <translation>(מזהה צומת: %1)</translation> </message> <message> <source>via %1</source> @@ -1817,14 +2136,6 @@ <translation>תעבורה יוצאת</translation> </message> <message> - <source>Yes</source> - <translation>כן</translation> - </message> - <message> - <source>No</source> - <translation>לא</translation> - </message> - <message> <source>Unknown</source> <translation>לא ידוע</translation> </message> @@ -1860,6 +2171,18 @@ <translation>סכום כרשות לבקשה. ניתן להשאיר זאת ריק כדי לא לבקש סכום מסוים.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>תווית אופצינלית לצירוף לכתובת קבלה חדשה (לשימושך לזיהוי חשבונות). היא גם מצורפת לבקשת התשלום.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>הודעה אוצפציונלית מצורפת לבקשת התשלום אשר ניתן להציגה לשולח.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&יצירת כתובת קבלה חדשה</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>ניקוי של כל השדות בטופס.</translation> </message> @@ -1911,56 +2234,60 @@ <source>Copy amount</source> <translation>העתקת הסכום</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>לא ניתן לשחרר את הארנק.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>לא ניתן לייצר כתובת %1 חדשה</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>קוד QR</translation> + <source>Request payment to ...</source> + <translation>בקשת תשלום לטובת…</translation> </message> <message> - <source>Copy &URI</source> - <translation>העתקת &כתובת משאב</translation> + <source>Address:</source> + <translation>כתובת:</translation> </message> <message> - <source>Copy &Address</source> - <translation>העתקת &כתובת</translation> + <source>Amount:</source> + <translation>סכום:</translation> </message> <message> - <source>&Save Image...</source> - <translation>&שמירת תמונה…</translation> + <source>Label:</source> + <translation>תוית:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>בקשת תשלום אל %1</translation> - </message> - <message> - <source>Payment information</source> - <translation>פרטי תשלום</translation> + <source>Message:</source> + <translation>הודעה:</translation> </message> <message> - <source>URI</source> - <translation>כתובת</translation> + <source>Wallet:</source> + <translation>ארנק:</translation> </message> <message> - <source>Address</source> - <translation>כתובת</translation> + <source>Copy &URI</source> + <translation>העתקת &כתובת משאב</translation> </message> <message> - <source>Amount</source> - <translation>סכום</translation> + <source>Copy &Address</source> + <translation>העתקת &כתובת</translation> </message> <message> - <source>Label</source> - <translation>תוית</translation> + <source>&Save Image...</source> + <translation>&שמירת תמונה…</translation> </message> <message> - <source>Message</source> - <translation>הודעה</translation> + <source>Request payment to %1</source> + <translation>בקשת תשלום אל %1</translation> </message> <message> - <source>Wallet</source> - <translation>ארנק</translation> + <source>Payment information</source> + <translation>פרטי תשלום</translation> </message> </context> <context> @@ -2006,7 +2333,7 @@ </message> <message> <source>Inputs...</source> - <translation>קלטים…</translation> + <translation>קלט...</translation> </message> <message> <source>automatically selected</source> @@ -2062,7 +2389,7 @@ </message> <message> <source>Warning: Fee estimation is currently not possible.</source> - <translation>אזהרה</translation> + <translation>אזהרה: שערוך העמלה לא אפשרי כעת.</translation> </message> <message> <source>Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. @@ -2109,6 +2436,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>אבק:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>הסתרת הגדרות עמלת עסקה</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>כאשר יש פחות נפח עסקאות מאשר מקום בבלוק, כורים וכן צמתות מקשרות יכולות להכתיב עמלות מינימום. התשלום של עמלת מינימום הנו תקין, אך יש לקחת בחשבון שהדבר יכול לגרום לעסקה שלא תאושר ברגע שיש יותר ביקוש לעסקאות ביטקוין מאשר הרשת יכולה לעבד.</translation> </message> @@ -2177,14 +2508,50 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%1 (%2 בלוקים)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>י&צירת לא חתומה</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>יוצר עסקת ביטקוין חתומה חלקית (PSBT) לשימוש עם ארנק %1 לא מחובר למשל, או עם PSBT ארנק חומרה תואם.</translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation>מתוך ארנק '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 אל '%2'</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 ל %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>האם ברצונך לשמור עסקה זו כטיוטה?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>לשלוח?</translation> </message> <message> + <source>Create Unsigned</source> + <translation>יצירת לא חתומה</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>שמירת נתוני העיסקה</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>עיסקה חתומה חלקית (בינארי) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT נשמרה</translation> + </message> + <message> <source>or</source> <translation>או</translation> </message> @@ -2193,6 +2560,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>תוכלו להגדיל את העמלה מאוחר יותר (איתות Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>בבקשה לסקור את העיסקה המוצעת. הדבר יצור עיסקת ביטקוין חתומה חלקית (PSBT) אשר ניתן לשמור או להעתיק ואז לחתום עם למשל ארנק לא מקוון %1, או עם ארנק חומרה תואם-PSBT.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>אנא עברו שוב על העסקה שלכם.</translation> </message> @@ -2209,10 +2580,26 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>סכום כולל</translation> </message> <message> + <source>To review recipient list click "Show Details..."</source> + <translation>כדי לסקור את רשימת המקבלים יש להקיש "הצגת פרטים..."</translation> + </message> + <message> <source>Confirm send coins</source> <translation>אימות שליחת מטבעות</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>אישור הצעת עיסקה</translation> + </message> + <message> + <source>Send</source> + <translation>שליחה</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>יתרת צפייה-בלבד</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>כתובת הנמען שגויה. נא לבדוק שוב.</translation> </message> @@ -2308,6 +2695,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>הסרת רשומה זו</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>הסכום לשליחה במטבע הנבחר</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>העמלה תנוכה מהסכום שנשלח. הנמען יקבל פחות ביטקוינים ממה שהזנת בשדה הסכום. אם נבחרו מספר נמענים, העמלה תחולק באופן שווה.</translation> </message> @@ -2407,7 +2798,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation>ניתן לחתום על ההודעה כדי להוכיח שכתובת הביטקוין הזו בבעלותך.</translation> + <translation>ניתן לחתום על ההודעה כדי להוכיח שכתובת ביטקוין זו בבעלותך</translation> </message> <message> <source>Sign &Message</source> @@ -2434,6 +2825,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>כתובת הביטקוין שאתה נחתמה ההודעה</translation> </message> <message> + <source>The signed message to verify</source> + <translation>ההודעה החתומה לאימות</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>החתימה שניתנת כאשר ההודעה נחתמה</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>ניתן לאמת את ההודעה כדי להבטיח שהיא נחתמה עם כתובת הביטקוין הנתונה</translation> </message> @@ -2466,6 +2865,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>שחרור הארנק בוטל.</translation> </message> <message> + <source>No error</source> + <translation>אין שגיאה</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>המפתח הפרטי לכתובת שהוכנסה אינו זמין.</translation> </message> @@ -2640,12 +3043,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>מפתח פלט</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(האישור לא אומת)</translation> + </message> + <message> <source>Merchant</source> <translation>סוחר</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>מטבעות מופקים חייבים להבשיל במשך %1 בלוקים לפני שניתן לבזבזם. כשהפקתם בלוק זה, הבלוק שודר לרשת לצורך הוספה לבלוקצ'יין. אם הבלוק לא יתווסף לבלוקצ'יין, מצב הבלוק ישונה ל "לא התקבל" ולא יהיה ניתן לבזבזו. מצב זה עלול לקרות כאשר שרת ביטקוין אחר מפיק בלוק בהפרש של כמה שניות משלכם.</translation> + <translation>מטבעות מופקים חייבים להבשיל במשך %1 בלוקים לפני שניתן לבזבזם. כשהפקתם בלוק זה, הבלוק שודר לרשת לצורך הוספה לבלוקצ'יין. אם הבלוק לא יתווסף לבלוקצ'יין, מצב הבלוק ישונה ל"לא התקבל" ולא יהיה ניתן לבזבזו. מצב זה עלול לקרות כאשר צומת אחרת מפיקה בלוק בהפרש של כמה שניות משלכם.</translation> </message> <message> <source>Debug information</source> @@ -2926,11 +3333,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Exporting Failed</source> - <translation>יצוא נכשל</translation> + <translation>הייצוא נכשל</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> - <translation>אירעה שגיאה בעת ניסיון שמירת היסטוריית ההעברות אל %1.</translation> + <translation>הייתה שגיאה בניסיון לשמור את היסטוריית העסקאות אל %1.</translation> </message> <message> <source>Exporting Successful</source> @@ -2938,7 +3345,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>The transaction history was successfully saved to %1.</source> - <translation>היסטוריית ההעברות נשמרה בהצלחה אל %1.</translation> + <translation>היסטוריית העסקאות נשמרה בהצלחה אל %1.</translation> </message> <message> <source>Range:</source> @@ -2963,15 +3370,35 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>סגירת ארנק</translation> </message> <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>האם אכן ברצונך לסגור את הארנק <i>%1</i>?</translation> + </message> + <message> <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>סגירת הארנק למשך זמן רב מדי יכול לגרור את הצורך לסינכרון מחדש של כל השרשרת אם אופצית הגיזום אקטיבית.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>סגירת כל הארנקים</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>האם אכן ברצונך לסגור את כל הארנקים?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>לא נטען ארנק.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>לא נטען ארנק. +עליך לגשת לקובץ > פתיחת ארנק כדי לטעון ארנק. +- או -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>יצירת ארנק חדש</translation> </message> </context> <context> @@ -2990,7 +3417,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Do you want to increase the fee?</source> - <translation>להגדיל את העמלה?</translation> + <translation>האם ברצונך להגדיל את העמלה?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>האם ברצונך להכין עסיקה עם עמלה מוגברת?</translation> </message> <message> <source>Current fee:</source> @@ -3009,6 +3440,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>אישור הקפצת עמלה</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>לא ניתן לשמור את העסקה כטיוטה.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT הועתקה</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>אי אפשר לחתום על ההעברה.</translation> </message> @@ -3032,6 +3471,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>יצוא הנתונים בלשונית הנוכחית לקובץ</translation> </message> <message> + <source>Error</source> + <translation>שגיאה</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>לא ניתן לפענח PSBT מתוך לוח הגזירים (base64 שגוי) </translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>טעינת נתוני עיסקה</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>עיסקה חתומה חלקית (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>קובץ PSBT צריך להיות קטמן מ 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>לא מצליח לפענח PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>גיבוי הארנק</translation> </message> @@ -3075,10 +3538,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>גיזום: הסינכרון האחרון של הארנק עובר את היקף הנתונים שנגזמו. יש לבצע חידוש אידקסציה (נא להוריד את כל שרשרת הבלוקים שוב במקרה של צומת מקוצצת)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>שגיאה: סניה קלמה קריטית פנימית קרטה, פנה ל debug.log לפרטים</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>מקצץ את ה blockstore...</translation> </message> @@ -3091,14 +3550,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>ה %s מפתחים</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>לא מצליח ליצור מפתח שינוי כתובת. אין מפתחות במאגר הפנימי של המפתחות ולא מצליח ליצור מפתח כלשהו.</translation> - </message> - <message> - <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation>לא מצליח לנעול את תיקית הנתונים %s. %s כנראה כבר רץ.</translation> - </message> - <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> <translation>לא מצליח לספק קשרים ספציפיים ולגרום ל addrman למצוא קשרים חיצוניים יחדיו.</translation> </message> @@ -3120,7 +3571,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </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>קוד זה הינו גרסת טסט טרום-פרסומית. *שימוש על אחריותכם בלבד* אין לעשות שימוש בקוד לצרכי כריית בלוקים או אפליקציות מסחר.</translation> + <translation>זוהי בניית ניסיון טרום־פרסום – השימוש באחריותך – אין להשתמש בה לצורך כרייה או יישומי מסחר</translation> </message> <message> <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> @@ -3143,14 +3594,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>אזהרה: יתכן שלא נסכים לגמרי עם עמיתינו! יתכן שתצטרכו לשדרג או שצמתות אחרות יצטרכו לשדרג.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d מ 100 הבלוקים האחרונים הנם בעלי גירסה לא צפויה.</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s משובש. נסיון החילוץ נכשל.</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool חייב להיות לפחות %d מ״ב</translation> </message> @@ -3172,7 +3615,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Corrupted block database detected</source> - <translation>התגלה מסד נתוני מקטעים לא תקין</translation> + <translation>מסד נתוני בלוקים פגום זוהה</translation> + </message> + <message> + <source>Could not find asmap file %s</source> + <translation> קובץ asmap %s לא נמצא</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation> קובץ asmap %s לא נפרס</translation> </message> <message> <source>Do you want to rebuild the block database now?</source> @@ -3196,7 +3647,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Error loading %s: Wallet corrupted</source> - <translation>שגיאת טעינה %s: הארנק משובש.</translation> + <translation>שגיאת טעינה %s: הארנק משובש</translation> </message> <message> <source>Error loading %s: Wallet requires newer version of %s</source> @@ -3231,12 +3682,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>איתחול של תהליך בדיקות השפיות נכשל. %s בתהליך סגירה.</translation> </message> <message> + <source>Invalid P2P permission: '%s'</source> + <translation>הרשאת P2P שגויה: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation>סכום שגוי עבור -%s=<amount>: '%s'</translation> </message> <message> <source>Invalid amount for -discardfee=<amount>: '%s'</source> - <translation>סכום לא תקין של -discardfee=<amount>: '%s'</translation> + <translation>סכום שגוי של -discardfee=<amount>: '%s'</translation> </message> <message> <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> @@ -3247,6 +3702,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>התיקיה שהוגדרה "%s" לא קיימת.</translation> </message> <message> + <source>Unknown address type '%s'</source> + <translation>כתובת לא ידועה מסוג "%s"</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>סוג שינוי לא ידוע: "%s"</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>שדרוג מאגר נתוני txindex </translation> </message> @@ -3255,11 +3718,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>טעינת כתובות P2P...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>שגיאה: שטח הדיסק נמוך מדי! - </translation> - </message> - <message> <source>Loading banlist...</source> <translation>טוען רשימת חסומים...</translation> </message> @@ -3313,7 +3771,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Verifying blocks...</source> - <translation>המקטעים מאומתים…</translation> + <translation>באימות הבלוקים…</translation> </message> <message> <source>Wallet needed to be rewritten: restart %s to complete</source> @@ -3324,18 +3782,46 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>שגיאה: האזנה לתקשורת נכנ סת נכשלה (ההאזנה מחזירה שגיאה %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>כמות שגויה של -maxtxfee=<amount>: '%s' (נדרש לפחות minrelay עמלה של %s כדי למנוע עסקאות מלהתקע</translation> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s משובש. נסו להשתמש בכלי הארנק bitcoin-wallet כדי להציל או לשחזר מגיבוי..</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>אין אפשרות לשדרג ארנק מפוצל שאינו HD מבלי לתמוך במאגר המפתחות טרם הפיצול. בבקשה להשתמש בגירסת 169900 או שלא צויינה גירסה.</translation> </message> <message> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation>סכום העברה נמוך מדי לשליחה אחרי גביית העמלה</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>שגיאה זו יכלה לקרות אם הארנק לא נסגר באופן נקי והועלה לאחרונה עם מבנה מבוסס גירסת Berkeley DB חדשה יותר. במקרה זה, יש להשתמש בתוכנה אשר טענה את הארנק בפעם האחרונה.</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>זוהי עמלת העיסקה המרבית שתשלם (בנוסף לעמלה הרגילה) כדי לתעדף מניעת תשלום חלקי על פני בחירה רגילה של מטבע. </translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>עיסקה מחייבת שינוי כתובת, אך לא ניתן לייצרה. נא לקרוא תחילה ל keypoolrefill </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>יש צורך בבניה מחדש של מסד הנתונים ע"י שימוש ב -reindex כדי לחזור חזרה לצומת שאינה גזומה. הפעולה תוריד מחדש את כל שרשרת הבלוקים.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>שגיאה פטלית פנימית אירעה, לפירוט ראה את לוג הדיבאג.</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>לא מצליח להגדיר את -peerblockfilters ללא-blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>אין מספיק מקום בכונן!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>שגיאת קריאה ממסד הנתונים. סוגר את התהליך.</translation> </message> @@ -3348,6 +3834,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>שגיאה: שטח הדיסק קטן מדי עובר %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>שגיאה: Keypool עבר את המכסה, קרא תחילה ל keypoolrefill </translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>שיעור העמלה (%s) נמוך משיעור העמלה המינימלי המוגדר (%s)</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>אי תקינות כתובת -onion או hostname: '%s'</translation> </message> @@ -3357,7 +3851,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> - <translation>כמות לא תקינה עבור -paytxfee=<amount>: '%s' (חייבת להיות לפחות %s)</translation> + <translation>סכום שגוי של -paytxfee=<amount>: '%s' (נדרשת %s לפחות)</translation> </message> <message> <source>Invalid netmask specified in -whitelist: '%s'</source> @@ -3365,7 +3859,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Need to specify a port with -whitebind: '%s'</source> - <translation>עליך לציין פתחה עם -whitebind: '%s'</translation> + <translation>יש לציין פתחה עם -whitebind: '%s'</translation> + </message> + <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>לא הוגדר פרוקסי. יש להשתמש ב־ -proxy=<ip> או ב־ -proxy=<ip:port>.</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>מצב מצומצם לא ניתן לשימוש עם blockfilterindex</translation> </message> <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> @@ -3389,7 +3891,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Specified -walletdir "%s" is not a directory</source> - <translation>תיקיית הארנק שצויינה -walletdir "%s" אינה תיקייה</translation> + <translation>תיקיית הארנק שצויינה -walletdir "%s" אינה תיקיה</translation> </message> <message> <source>The specified config file %s does not exist @@ -3419,25 +3921,25 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Unable to create the PID file '%s': %s</source> - <translation>לא מצליח ליצור את קובץ PID '%s': %s</translation> + <translation>לא ניתן ליצור את קובץ PID '%s': %s</translation> </message> <message> <source>Unable to generate initial keys</source> - <translation>לא מצליח ליצור מפתחות ראשוניים</translation> + <translation>לא ניתן ליצור מפתחות ראשוניים</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>ערך -blockfilterindex %s לא ידוע.</translation> </message> <message> <source>Verifying wallet(s)...</source> - <translation>מאמת ארנק(ים)...</translation> + <translation>באימות הארנק(ים)...</translation> </message> <message> <source>Warning: unknown new rules activated (versionbit %i)</source> <translation>אזהרה: חוקים חדשים שאינם מוכרים שופעלו (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>שולה את כל העסקאות מתוך הארנק...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee נקבע לעמלות גבוהות מאד! עמלות גבוהות כאלו יכולות משולמות עבר עסקה בודדת.</translation> </message> @@ -3450,10 +3952,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>האורך הכולל של רצף התווים של גירסת הרשת (%i) גדול מהאורך המרבי המותר (%i). יש להקטין את המספר או האורך של uacomments.</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>אזהרה: הארנק משובש. הנתונים חולצו! המקור %s נשמר כ %s ב %s; אם היתרהאו העסקות אינן נכונות יש לבצע שיחזור מגיבוי.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s הוגדר מאד גבוה!</translation> </message> @@ -3498,10 +3996,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>אין מספיק כספים</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>אין אפשרות לבצע שדרוג של ארנק מפוצל שאינו HD ללא שדרוג לתמיכה של טרום פיצול של keypool .יש להשתמש ב -upgradewallet=169900 או -upgradewallet ללא ציון גירסה.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>אמדן גובה עמלה נכשל. Fallbackfee מנוטרל. יש להמתין מספר בלוקים או לשפעל את -fallbackfee</translation> </message> diff --git a/src/qt/locale/bitcoin_hi.ts b/src/qt/locale/bitcoin_hi.ts index bf67fd01f5..086a106c3d 100644 --- a/src/qt/locale/bitcoin_hi.ts +++ b/src/qt/locale/bitcoin_hi.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> @@ -23,15 +23,15 @@ </message> <message> <source>C&lose</source> - <translation>सी&लूज़</translation> + <translation>&बंद करें</translation> </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> @@ -43,47 +43,51 @@ </message> <message> <source>&Delete</source> - <translation>&मिटाए !!</translation> + <translation>&मिटाए</translation> </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> </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>ये भुगतान भेजने के लिए ये आपके बिटकॉइन पते हैं। हमेशा सिक्के भेजने से पहले राशि और प्राप्तकर्ता पते की जांच करें।</translation> + <translation>भुगतान करने के लिए ये आपके बिटकॉइन एड्रेस हैं। कॉइन भेजने से पहले राशि और गंतव्य एड्रेस की हमेशा जाँच करें </translation> </message> <message> <source>&Copy Address</source> - <translation>&पता कॉपी करें </translation> + <translation>&एड्रेस कॉपी करें</translation> </message> <message> <source>Copy &Label</source> - <translation>प्रतिलिप करे और चिन्हित करें</translation> + <translation>कॉपी &लेबल </translation> </message> <message> <source>&Edit</source> - <translation>&संशोधित करें </translation> + <translation>&बदलाव करें</translation> </message> <message> <source>Export Address List</source> - <translation>निर्यात पता सूची</translation> + <translation>एड्रेस की सूची निर्यात करें</translation> </message> <message> <source>Comma separated file (*.csv)</source> - <translation>कोमा द्वारा अलग की गई फ़ाइल (* .csv)</translation> + <translation>कौमा सेपरेटेड फाइल (* .csv)</translation> </message> <message> <source>Exporting Failed</source> @@ -91,22 +95,22 @@ </message> <message> <source>There was an error trying to save the address list to %1. Please try again.</source> - <translation>पता सूची को %1 में सहेजने का प्रयास करने में त्रुटि हुई। कृपया पुन: प्रयास करें।</translation> + <translation>एड्रेस की सूची को %1 में सहेजने का प्रयास करने में त्रुटि हुई। कृपया पुन: प्रयास करें।</translation> </message> </context> <context> <name>AddressTableModel</name> <message> <source>Label</source> - <translation>परचा</translation> + <translation>लेबल</translation> </message> <message> <source>Address</source> - <translation>पता</translation> + <translation>एड्रेस</translation> </message> <message> <source>(no label)</source> - <translation>(कोई परचा नहीं )</translation> + <translation>(लेबल नहीं है)</translation> </message> </context> <context> @@ -117,15 +121,19 @@ </message> <message> <source>Enter passphrase</source> - <translation>पहचान शब्द/अक्षर डालिए !</translation> + <translation>पासफ्रेज़ दर्ज करें</translation> </message> <message> <source>New passphrase</source> - <translation>नया पहचान शब्द/अक्षर डालिए !</translation> + <translation>नया पासफ्रेज़</translation> </message> <message> <source>Repeat new passphrase</source> - <translation>दोबारा नया पहचान शब्द/अक्षर डालिए !</translation> + <translation>नया पासफ्रेज़ दोबारा दर्ज करें </translation> + </message> + <message> + <source>Show passphrase</source> + <translation>पासफ्रेज़ उजागर करे</translation> </message> <message> <source>Encrypt wallet</source> @@ -168,26 +176,86 @@ <translation>वॉलेट को एन्क्रिप्ट किया गया है</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>वॉलेट में नया सुरक्षा संवाद दर्ज करें | कृपया दस या उससे अधिक, या फिर आठ या उससे अधिक अव्यवस्थित अंको से ही अपना सुरक्षा संवाद बनाएं ।</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>वॉलेट में पुराना एवं नया सुरक्षा संवाद दर्ज करें ।</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>याद रखें कि अपने बटुए (वॉलेट) एन्क्रिप्ट करना आपके कंप्यूटर को संक्रमित करने वाले मैलवेयर द्वारा आपके बिटकॉइन को चोरी होने से पूरी तरह से सुरक्षित नहीं कर सकता है।</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>बटुए "वॉलेट" को एन्क्रिप्ट किया जाना है</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>आपका बटुआ "वॉलेट" एन्क्रिप्टेड होने वाला है।</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>आपका बटुआ "वॉलेट" एन्क्रिप्ट हो गया है।</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> - </context> + <message> + <source>Wallet passphrase was successfully changed.</source> + <translation>वॉलेट पासफ़्रेज़ को सफलतापूर्वक बदल दिया गया था।</translation> + </message> + <message> + <source>Warning: The Caps Lock key is on!</source> + <translation>चेतावनी: कैप्स लॉक कुंजी चालू है!</translation> + </message> +</context> <context> <name>BanTableModel</name> - </context> + <message> + <source>IP/Netmask</source> + <translation>आईपी /नेटमास्क "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> + <translation>नेटवर्क से समकालिकरण जारी है ...</translation> </message> <message> <source>&Overview</source> @@ -215,18 +283,46 @@ <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>&Encrypt Wallet...</source> + <translation>और वॉलेट को गोपित "एन्क्रिप्ट" करें</translation> + </message> + <message> <source>&Backup Wallet...</source> <translation>&बैकप वॉलेट</translation> </message> <message> + <source>&Change Passphrase...</source> + <translation>और पासफ़्रेज़ बदलें</translation> + </message> + <message> <source>Wallet:</source> <translation>तिजोरी</translation> </message> <message> + <source>Send coins to a Bitcoin address</source> + <translation>इस पते पर बिटकौइन भेजें</translation> + </message> + <message> <source>Change the passphrase used for wallet encryption</source> <translation>पहचान शब्द/अक्षर जो वॉलेट एनक्रिपशन के लिए इस्तेमाल किया है उसे बदलिए!</translation> </message> @@ -267,6 +363,22 @@ <translation>नवीनतम</translation> </message> <message> + <source>Open a wallet</source> + <translation>बटुआ खोलें</translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>बटुआ बंद करें...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>बटुआ बंद करें</translation> + </message> + <message> + <source>Close All Wallets...</source> + <translation>सारे बटुएँ बंद करें...</translation> + </message> + <message> <source>Sent transaction</source> <translation>भेजी ट्रांजक्शन</translation> </message> @@ -286,6 +398,10 @@ <context> <name>CoinControlDialog</name> <message> + <source>Quantity:</source> + <translation>मात्रा :</translation> + </message> + <message> <source>Amount:</source> <translation>राशि :</translation> </message> @@ -302,6 +418,14 @@ <translation>पक्का</translation> </message> <message> + <source>yes</source> + <translation>हाँ</translation> + </message> + <message> + <source>no</source> + <translation>नहीं</translation> + </message> + <message> <source>(no label)</source> <translation>(कोई परचा नहीं )</translation> </message> @@ -392,6 +516,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -442,26 +569,18 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>&पता कॉपी करे</translation> - </message> - <message> - <source>Address</source> - <translation>पता</translation> - </message> - <message> - <source>Amount</source> - <translation>राशि</translation> + <source>Amount:</source> + <translation>राशि :</translation> </message> <message> - <source>Label</source> - <translation>परचा</translation> + <source>Wallet:</source> + <translation>तिजोरी</translation> </message> <message> - <source>Wallet</source> - <translation>वॉलेट</translation> + <source>Copy &Address</source> + <translation>&पता कॉपी करे</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -484,6 +603,10 @@ <translation>सिक्के भेजें|</translation> </message> <message> + <source>Quantity:</source> + <translation>मात्रा :</translation> + </message> + <message> <source>Amount:</source> <translation>राशि :</translation> </message> @@ -564,7 +687,15 @@ <name>TransactionDesc</name> <message> <source>Date</source> - <translation>taareek</translation> + <translation>दिनांक</translation> + </message> + <message> + <source>Source</source> + <translation>स्रोत</translation> + </message> + <message> + <source>Generated</source> + <translation>उत्पन्न</translation> </message> <message> <source>unknown</source> @@ -629,6 +760,10 @@ </context> <context> <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>बटुआ बंद करें</translation> + </message> </context> <context> <name>WalletFrame</name> @@ -650,10 +785,18 @@ <source>Export the data in the current tab to a file</source> <translation>डेटा को मौजूदा टैब से एक फ़ाइल में निर्यात करें</translation> </message> + <message> + <source>Error</source> + <translation>भूल</translation> + </message> </context> <context> <name>bitcoin-core</name> <message> + <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> + <translation>यह एक पूर्व-रिलीज़ परीक्षण बिल्ड है - अपने जोखिम पर उपयोग करें - खनन या व्यापारी अनुप्रयोगों के लिए उपयोग न करें</translation> + </message> + <message> <source>Verifying blocks...</source> <translation>ब्लॉक्स जाँचे जा रहा है...</translation> </message> diff --git a/src/qt/locale/bitcoin_hr.ts b/src/qt/locale/bitcoin_hr.ts index 0d0a2e6765..98c1abaab5 100644 --- a/src/qt/locale/bitcoin_hr.ts +++ b/src/qt/locale/bitcoin_hr.ts @@ -7,7 +7,7 @@ </message> <message> <source>Create a new address</source> - <translation>Dodajte novu adresu</translation> + <translation>Stvoriti novu adresu</translation> </message> <message> <source>&New</source> @@ -70,10 +70,6 @@ <translation>Ovo su vaše Bitcoin adrese za slanje novca. Uvijek provjerite iznos i adresu primatelja prije slanja novca.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <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>&Kopirajte adresu</translation> </message> @@ -616,11 +612,7 @@ <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> - <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> <context> <name>CoinControlDialog</name> <message> @@ -1118,10 +1110,6 @@ <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> @@ -1254,10 +1242,6 @@ <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> @@ -1432,7 +1416,22 @@ <source>Current total balance in watch-only addresses</source> <translation>Trenutno ukupno stanje na isključivo promatranim adresama</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dijalog</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Ukupni iznos</translation> + </message> + <message> + <source>or</source> + <translation>ili</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1692,10 +1691,6 @@ <translation>Lanac blokova</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Trenutni broj blokova</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memorijski bazen</translation> </message> @@ -1740,10 +1735,6 @@ <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> @@ -1784,10 +1775,6 @@ <translation>Usluge</translation> </message> <message> - <source>Ban Score</source> - <translation>Broj zabrana</translation> - </message> - <message> <source>Connection Time</source> <translation>Trajanje veze</translation> </message> @@ -1936,14 +1923,6 @@ <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> @@ -2034,12 +2013,28 @@ <source>Copy amount</source> <translation>Kopiraj iznos</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Ne može se otključati novčanik.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR kôd</translation> + <source>Amount:</source> + <translation>Iznos:</translation> + </message> + <message> + <source>Label:</source> + <translation>Oznaka</translation> + </message> + <message> + <source>Message:</source> + <translation>Poruka:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Novčanik:</translation> </message> <message> <source>Copy &URI</source> @@ -2061,30 +2056,6 @@ <source>Payment information</source> <translation>Informacije o uplati</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adresa</translation> - </message> - <message> - <source>Amount</source> - <translation>Iznos</translation> - </message> - <message> - <source>Label</source> - <translation>Oznaka</translation> - </message> - <message> - <source>Message</source> - <translation>Poruka</translation> - </message> - <message> - <source>Wallet</source> - <translation>Novčanik</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2232,6 +2203,11 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation>Prah:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Sakrijte postavke za transakcijske provizije +</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Kada je kapacitet transakcija manja od prostora u blokovima, rudari i čvorovi prenositelji mogu zatražiti minimalnu naknadu. Prihvatljivo je platiti samo ovu minimalnu naknadu, ali budite svjesni da ovime može nastati transakcija koja se nikad ne potvrđuje čim je potražnja za korištenjem Bitcoina veća nego što mreža može obraditi.</translation> </message> @@ -2447,6 +2423,10 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation>Obrišite ovaj zapis</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Iznos za slanje u odabranoj valuti </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> @@ -3117,12 +3097,12 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Držanje novčanik zatvorenim predugo može rezultirati ponovnom sinkronizacijom cijelog lanca ako je obrezivanje uključeno.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nije pokrenut nikakav novčanik.</translation> + <source>Create a new wallet</source> + <translation>Stvorite novi novčanik</translation> </message> </context> <context> @@ -3183,6 +3163,10 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation>Izvoz podataka iz trenutnog lista u datoteku</translation> </message> <message> + <source>Error</source> + <translation>Greška</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Arhiviranje novčanika</translation> </message> @@ -3226,10 +3210,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <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>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> @@ -3242,10 +3222,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation>Ekipa %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Ne može se generirati ključ adrese za ostatak. Nema ključeva u unutarnjem bazenu ključeva i ne mogu se generirati nikakvi ključevi.</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> @@ -3294,14 +3270,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <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> @@ -3418,10 +3386,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation>Pokreće se popis P2P adresa...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Pogreška: Nema dovoljno prostora na disku!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Pokreće se popis zabrana...</translation> </message> @@ -3604,10 +3568,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <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> @@ -3620,10 +3580,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <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>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> @@ -3668,10 +3624,6 @@ Napomena: Budući da se naknada računa po bajtu, naknada od "100 satošija po k <translation>Nedovoljna sredstva</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> diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts index 34c8b91844..ccc860b7d2 100644 --- a/src/qt/locale/bitcoin_hu.ts +++ b/src/qt/locale/bitcoin_hu.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>A cím vagy címke szerkeszteséhez kattintson a jobb gombbal</translation> + <translation>Cím vagy címke szerkesztéséhez kattints a jobb gombbal</translation> </message> <message> <source>Create a new address</source> @@ -59,19 +59,20 @@ </message> <message> <source>Sending addresses</source> - <translation>Küldési cím</translation> + <translation>Küldési címek</translation> </message> <message> <source>Receiving addresses</source> - <translation>Fogadási cím</translation> + <translation>Fogadási címek</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>Ezek a Bitcoin címeid kifizetések küldéséhez. Mindíg ellenőrizd az összeget és a fogadó címet mielőtt coinokat küldenél.</translation> + <translation>Ezek a te Bitcoin címeid kifizetések küldéséhez. Mindíg ellenőrizd az összeget és a fogadó címet mielőtt coinokat küldenél.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Ezek a fizetések fogadására szolgáló Bitcoin-címeid. Használd az "Új fogadócím létrehozása" gombot a fogadás fülön új cím létrehozásához.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Ezek a Bitcoin címeid amelyeken fogadni tudsz Bitcoin utalásokat. Az "Új cím létrehozása" gombbal tudsz új címet létrehozni. Aláírni csak korábbi egyessel kezdődő címekkel lehet.</translation> </message> <message> <source>&Copy Address</source> @@ -83,7 +84,7 @@ </message> <message> <source>&Edit</source> - <translation>Szerkesztés</translation> + <translation>&Szerkesztés</translation> </message> <message> <source>Export Address List</source> @@ -482,6 +483,30 @@ <translation>Naprakész</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&PSBT betöltése fájlból.</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Részlegesen aláírt Bitcoin tranzakció (PSBT) betöltése</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>PSBT betöltése vágólapról</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Részlegesen aláírt Bitcoin tranzakció (PSBT) betöltése vágólapról</translation> + </message> + <message> + <source>Node window</source> + <translation>Csomópont ablak</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Nyisd meg a hibaellenőrző és diagnosztizáló konzolt.</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&Küldő címek</translation> </message> @@ -490,6 +515,10 @@ <translation>&Fogadó címek</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Bitcoin URI megnyitása</translation> + </message> + <message> <source>Open Wallet</source> <translation>Tárca megnyitása</translation> </message> @@ -506,10 +535,26 @@ <translation>Tárca bezárása</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Összes tárca bezárása...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Összes tárca bezárása</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>A %1 súgó megjelenítése a Bitcoin lehetséges parancssori kapcsolóinak listájával</translation> </message> <message> + <source>&Mask values</source> + <translation>&Értékek elrejtése</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Értékek elrejtése az Áttekintés fülön</translation> + </message> + <message> <source>default wallet</source> <translation>Alapértelmezett tárca</translation> </message> @@ -550,6 +595,10 @@ <translation>Hiba: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>Vigyázz: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>Dátum: %1 @@ -613,8 +662,12 @@ <translation>A tárca <b>titkosítva</b> és jelenleg <b>bezárva</b>.</translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Végzetes hiba történt. A Bitcoin működése nem biztonságos és hamarosan leáll.</translation> + <source>Original message:</source> + <translation>Eredeti üzenet:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Végzetes hiba történt %1 nem tud biztonságban továbblépni így most kilép.</translation> </message> </context> <context> @@ -806,6 +859,10 @@ <translation>A tárcához tartozó privát kulcsok letiltása. Azok a tárcák, melyeknél a privát kulcsok le vannak tiltva, nem tartalmaznak privát kulcsokat és nem tartalmazhatnak HD magot vagy importált privát kulcsokat. Ez azoknál a tárcáknál ideális, melyeket csak megfigyelésre használnak.</translation> </message> <message> + <source>Disable Private Keys</source> + <translation>Kapcsold ki a Privát Kódot</translation> + </message> + <message> <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> <translation>Üres tárca készítése. Az üres tárcák kezdetben nem tartalmaznak privát kulcsokat vagy szkripteket. Később lehetséges a privát kulcsok vagy címek importálása avagy egy HD mag beállítása.</translation> </message> @@ -813,7 +870,19 @@ <source>Make Blank Wallet</source> <translation>Üres tárca készítése</translation> </message> - </context> + <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Leírók használata scriptPubKey menedzseléshez</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Descriptor Tárca</translation> + </message> + <message> + <source>Create</source> + <translation>Létrehozás</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -853,6 +922,14 @@ <translation>A megadott "%1" cím nem egy érvényes Bitcoin-cím.</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>A(z) "%1" már egy létező fogadó cím "%2" névvel és nem lehet küldő címként hozzáadni.</translation> + </message> + <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>A megadott "%1" cím már szerepel a címjegyzékben "%2" néven.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Nem sikerült a tárca megnyitása</translation> </message> @@ -973,7 +1050,15 @@ <source>%n GB of free space available</source> <translation><numerusform>%n GB elérhető szabad hely</numerusform><numerusform>%n GB elérhető szabad hely</numerusform></translation> </message> - </context> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(%n GB szükségesnek)</numerusform><numerusform>(%n GB szükségesnek)</numerusform></translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB szükséges a teljes lánchoz)</numerusform><numerusform>(%n GB szükséges a teljes lánchoz)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -1020,10 +1105,26 @@ <source>Hide</source> <translation>Elrejtés</translation> </message> - </context> + <message> + <source>Esc</source> + <translation>Kilépés</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 szinkronizálás alatt. Fejléceket és blokkokat tölt le a felektől, majd érvényesíti, amíg el nem éri a blokklánc tetejét.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Ismeretlen. Fejlécek szinkronizálása (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Nyisd meg a bitcoin címedet</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1082,10 +1183,6 @@ <translation>Megmutatja, hogy az alapértelmezett SOCKS5 proxy van-e használatban, hogy elérje a párokat ennél a hálózati típusnál.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Za dostop do soležnikov preko skritih storitev Tor uporabi drug posredniški strežnik SOCKS&5:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Ikon elrejtése a tálcáról.</translation> </message> @@ -1218,10 +1315,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Csatlakozás a Bitcoin hálózathoz külön SOCKS5 proxy használatával a Tor rejtett szolgáltatásainak eléréséhez.</translation> - </message> - <message> <source>&Window</source> <translation>&Ablak</translation> </message> @@ -1262,10 +1355,18 @@ <translation>Mutassa a pénzküldés beállításait vagy ne.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Csatlakozás a Bitcoin hálózathoz külön SOCKS5 proxy használatával a Tor rejtett szolgáltatásainak eléréséhez.</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&Harmadik féltől származó tranzakció URL-ek</translation> </message> <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Az ebben a párbeszédablakban beállított opciók felülírásra kerültek a parancssor által vagy a konfigurációs fájlban:</translation> + </message> + <message> <source>&OK</source> <translation>&OK</translation> </message> @@ -1392,6 +1493,133 @@ <source>Current total balance in watch-only addresses</source> <translation>A csak megfigyelt címek jelenlegi teljes egyenlege</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Diszkrét mód aktiváva az áttekintés fülün. Az értékek újbóli megjelenítéséhez kapcsold ki a Beállítások->Értékek maszkolását</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Párbeszéd</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Tx aláírása</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Tx kiküldése</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Másolás vágólapra</translation> + </message> + <message> + <source>Save...</source> + <translation>Mentés...</translation> + </message> + <message> + <source>Close</source> + <translation>Bezárás</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Tranzakció betöltése sikertelen: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Tranzakció aláírása sikertelen: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Több input-ot nem tudok aláírni.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>%1 input aláírva, de több alárásra van szükség.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Tranzakció sikeresen aláírva. Szétküldésre kész.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Imseretlen hiba a tranzakció feldolázásakor.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Tranzakció sikeresen szétküldve. Transaction ID: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Tranzakció szétküldése sikertelen: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT vágólapra másolva.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Tranzakció adatainak mentése</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Részlegesen Aláírt Tranzakció (PSBT bináris) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT háttértárolóra mentve.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation> * Küldés %1 to %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Nem tudok tranzakciós díjat vagy teljes tranzakció értéket kalkulálni.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Fizetendő tranzakciós díj:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Teljes összeg</translation> + </message> + <message> + <source>or</source> + <translation>vagy</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>A tranzakciónak %1 aláíratlan bejövő érteke van.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>A tranzakcióból adatok hiányoznak a bejövő oldalon.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Még aláírások szükségesen a tranzakcióhoz.</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(De ez a tárca nem tudja aláírni a tranzakciókat.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(De ebben a tárcában nincsenek meg a megfelelő kulcsok.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Tranzakció teljesen aláírva és szétküldésre kész.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Tranzakció állapota ismeretlen.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1408,10 +1636,22 @@ <translation>URI kezelés</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' nem érvényes egységes erőforrás azonosító (URI). Használd helyette a 'bitcoin'-t.</translation> + </message> + <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>A fizetési kérelmet nem lehet feldolgozni, mert a BIP70 nem támogatott.</translation> + </message> + <message> <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> <translation>A BIP70 széleskörű biztonsági hiányosságai következtében határozottan ajánljuk, hogy hagyjon figyelmen kívül bármiféle kereskedelmi utasítást, amely a tárca váltására készteti.</translation> </message> <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Ha ezt a hibaüzenetet kapod, meg kell kérned a kereskedőt, hogy biztosítson BIP21 kompatibilis URI-t.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>Érvénytelen fizetési cím %1</translation> </message> @@ -1546,6 +1786,10 @@ <translation>Hiba: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Beállítások betöltése sikertelen: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 még nem lépett ki biztonságosan...</translation> </message> @@ -1573,6 +1817,10 @@ <translation>Hiba lépett fel az URI QR kóddá alakításakor.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>QR kód támogatás nem elérhető.</translation> + </message> + <message> <source>Save QR Code</source> <translation>QR Kód Mentése</translation> </message> @@ -1608,6 +1856,18 @@ <translation>Adatkönyvtár</translation> </message> <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>Az adat könyvárhoz kívánt nem alapértelmezett elérési úthoz használd a '%1' opciót</translation> + </message> + <message> + <source>Blocksdir</source> + <translation>Blokk könyvtár</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>Az blokkk könyvárhoz kívánt nem alapértelmezett elérési úthoz használd a '%1' opciót</translation> + </message> + <message> <source>Startup time</source> <translation>Bekapcsolás ideje</translation> </message> @@ -1628,10 +1888,6 @@ <translation>Blokklánc</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Aktuális blokkok száma</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memória Halom</translation> </message> @@ -1648,6 +1904,10 @@ <translation>Tárca:</translation> </message> <message> + <source>(none)</source> + <translation>(nincs)</translation> + </message> + <message> <source>&Reset</source> <translation>&Visszaállítás</translation> </message> @@ -1672,10 +1932,6 @@ <translation>Peer kijelölése a részletes információkért</translation> </message> <message> - <source>Whitelisted</source> - <translation>Engedélyezett</translation> - </message> - <message> <source>Direction</source> <translation>Irány</translation> </message> @@ -1696,10 +1952,26 @@ <translation>Szinkronizált Blokkok</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>A megadott "Önálló rendszer" használom a peer választás diverzifikálásához.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Felvett AS (önálló rendszer)</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> <message> + <source>Node window</source> + <translation>Csomópont ablak</translation> + </message> + <message> + <source>Current block height</source> + <translation>Jelenlegi legmagasabb blokkszám</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>A %1 debug log fájl megnyitása a jelenlegi könyvtárból. Ez néhány másodpercig eltarthat nagyobb log fájlok esetén.</translation> </message> @@ -1712,12 +1984,12 @@ <translation>Betűméret növelése</translation> </message> <message> - <source>Services</source> - <translation>Szolgáltatások</translation> + <source>Permissions</source> + <translation>Jogosultságok</translation> </message> <message> - <source>Ban Score</source> - <translation>Kazenske točke</translation> + <source>Services</source> + <translation>Szolgáltatások</translation> </message> <message> <source>Connection Time</source> @@ -1868,14 +2140,6 @@ <translation>Kimenő</translation> </message> <message> - <source>Yes</source> - <translation>Igen</translation> - </message> - <message> - <source>No</source> - <translation>Nem</translation> - </message> - <message> <source>Unknown</source> <translation>Ismeretlen</translation> </message> @@ -1911,6 +2175,14 @@ <translation>Egy opcionálisan kérhető összeg. Hagyja üresen, vagy írjon be nullát, ha nem kívánja használni.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Egy opcionális címke, amit hozzá lehet rendelni az új fogadó címhez (amit használhatsz a számla azonosításához). E mellett hozzá lesz csatolva a fizetési kérelemhez is.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Egy opcionális üzenet ami a fizetési kérelemhez van fűzve és valószínűleg meg lesz jelenítve a fizető oldalán.</translation> + </message> + <message> <source>&Create new receiving address</source> <translation>&Új fogadócím létrehozása</translation> </message> @@ -1966,56 +2238,60 @@ <source>Copy amount</source> <translation>Összeg másolása</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Nem sikerült a tárca megnyitása</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Cím generálása sikertelen %1 </translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR kód</translation> + <source>Request payment to ...</source> + <translation>Fizetési igény ...-nek</translation> </message> <message> - <source>Copy &URI</source> - <translation>&URI másolása</translation> + <source>Address:</source> + <translation>Cím:</translation> </message> <message> - <source>Copy &Address</source> - <translation>&Cím másolása</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>&Kép mentése</translation> + <source>Amount:</source> + <translation>Összeg:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Fizetés kérése a %1 -hez</translation> + <source>Label:</source> + <translation>Címke:</translation> </message> <message> - <source>Payment information</source> - <translation>Fizetési információ</translation> + <source>Message:</source> + <translation>Üzenet:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Tárca:</translation> </message> <message> - <source>Address</source> - <translation>Cím</translation> + <source>Copy &URI</source> + <translation>&URI másolása</translation> </message> <message> - <source>Amount</source> - <translation>Összeg</translation> + <source>Copy &Address</source> + <translation>&Cím másolása</translation> </message> <message> - <source>Label</source> - <translation>Címke</translation> + <source>&Save Image...</source> + <translation>&Kép mentése</translation> </message> <message> - <source>Message</source> - <translation>Üzenet</translation> + <source>Request payment to %1</source> + <translation>Fizetés kérése a %1 -hez</translation> </message> <message> - <source>Wallet</source> - <translation>Tárca</translation> + <source>Payment information</source> + <translation>Fizetési információ</translation> </message> </context> <context> @@ -2120,6 +2396,14 @@ <translation>Figyelem: A hozzávetőleges díjszámítás jelenleg nem lehetséges.</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>Add meg a választott tranzakciós díjat kB (1000 bájt) -onként a tranzakció virtuális méretére számolva. + +Figyelem: Mivel bájtonként lesz a dj kiszámolva ezért a "100 satoshi per kB" egy 500 bájtos (fél kB) tranzakciónál ténylegesen 50 satoshi lesz.</translation> + </message> + <message> <source>per kilobyte</source> <translation>kilobájtonként</translation> </message> @@ -2156,6 +2440,18 @@ <translation>Por-határ:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Rejtsd el a tranzakciós költségek beállításait</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Ha kevesebb a tranzakció mint amennyi hely lenne egy blokkban, akkor a bányászok és a többi node megkövetelheti a minimum díjat. E minimum díjat fizetni elegendő lehet, de tudnod kell, hogy ez esetleg soha nem konfirmálódó tranzakciót eredményezhet ahogy a tranzakciók száma magasabb lesz mint a network által megengedett.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>A túl alacsony illeték a tranzakció soha be nem teljesülését eredményezheti (olvassa el az elemleírást)</translation> + </message> + <message> <source>Confirmation time target:</source> <translation>Várható megerősítési idő:</translation> </message> @@ -2164,6 +2460,10 @@ <translation>Replace-By-Fee bekapcsolása</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>A With Replace-By-Fee (BIP-125) funkciót használva küldés után is megemelheted a tranzakciós díjat. Ha ezt nem használod akkor magasabb díjat érdemes használni, hogy kisebb legyen a késedelem.</translation> + </message> + <message> <source>Clear &All</source> <translation>Mindent &töröl</translation> </message> @@ -2212,18 +2512,50 @@ <translation>%1 (%2 blokov)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>&Aláírás nélkül létrehozása Unsigned</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Létrehoz egy Részlegesen Aláírt Bitcoin Tranzakciót (PSBT) melyet offline %1 tárcával vagy egy PSBT kompatibilis hardver tárcával használhatsz.</translation> + </message> + <message> <source> from wallet '%1'</source> <translation>A "%1" tárcától</translation> </message> <message> + <source>%1 to '%2'</source> + <translation>%1 -től '%2-ig'</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 do %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Piszkozatba teszed ezt a tranzakciót?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Biztosan el akarja küldeni?</translation> </message> <message> + <source>Create Unsigned</source> + <translation>Aláíratlan létrehozása</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Tranzakció adatainak mentése</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Részlegesen Aláírt Tranzakció (PSBT bináris) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PBST elmentve</translation> + </message> + <message> <source>or</source> <translation>vagy</translation> </message> @@ -2232,14 +2564,46 @@ <translation>Később növelheti a tranzakció díját (lásd Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Kérlek nézd át a tranzakciós javaslatot. Ez létrehoz egy Részlegesen Aláírt Bitcoin Tranzakciót (PSBT) amit elmenthetsz vagy kimásolhatsz. Aztán aláírhatod: offline %1 tárcával vagy egy PSBT kompatibilis hardver tárcával.</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Kérjük, hogy ellenőrizze le a tranzakcióját.</translation> + </message> + <message> <source>Transaction fee</source> <translation>Tranzakciós díj</translation> </message> <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Nem jelzek Replace-By-Fee, BIP-125-t</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Teljes összeg</translation> + </message> + <message> + <source>To review recipient list click "Show Details..."</source> + <translation>A címzett lista ellenőrzéséhez kattintson a "További részletek" gombra.</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Összeg küldésének megerősítése</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Tranzakció javaslat megerősítése</translation> + </message> + <message> + <source>Send</source> + <translation>Küldés</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Egyenleg csak megfigyelésre</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>A fogadó címe érvénytelen. Kérem ellenőrizze.</translation> </message> @@ -2271,6 +2635,10 @@ <source>Payment request expired.</source> <translation>A fizetési kérelem lejárt.</translation> </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Becsülhetőn %n blokkon belül kerül be.</numerusform><numerusform>Estimated to begin confirmation within %n blocks.</numerusform></translation> + </message> <message> <source>Warning: Invalid Bitcoin address</source> <translation>Figyelmeztetés: Érvénytelen Bitcoin cím</translation> @@ -2331,6 +2699,10 @@ <translation>Ez a bejegyzés eltávolítása</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>A küldendő összeg a választott egységben.</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>Znesek plačila bo zmanjšan za znesek provizije. Prejemnik bo prejel manjše število kovancev, kot je bil vnešeni znesek. Če je prejemnikov več, bo provizija med njih enakomerno porazdeljena.</translation> </message> @@ -2457,6 +2829,14 @@ <translation>Bitcoin cím, amivel aláírta az üzenetet</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Az aláírt üzenet ellenőrzésre</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>A kapott aláírás amikor az üzenet alá lett írva.</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Ellenőrizze az üzenetet, hogy valóban a megjelölt Bitcoin címmel van-e aláírva</translation> </message> @@ -2489,6 +2869,10 @@ <translation>Tárca megnyitása megszakítva</translation> </message> <message> + <source>No error</source> + <translation>Nincs hiba</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>A megadott cím privát kulcsa nem található.</translation> </message> @@ -2530,6 +2914,10 @@ </context> <context> <name>TransactionDesc</name> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>%n további blokkra megnyitva</numerusform><numerusform>%n további blokkra megnyitva</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>%1 -ig megnyitva</translation> @@ -2606,6 +2994,10 @@ <source>Credit</source> <translation>Jóváírás</translation> </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>beérik %n blokk múlva</numerusform><numerusform>beérik %n blokk múlva</numerusform></translation> + </message> <message> <source>not accepted</source> <translation>elutasítva</translation> @@ -2647,10 +3039,18 @@ <translation>Tranzakció teljes mérete</translation> </message> <message> + <source>Transaction virtual size</source> + <translation>A tranzakció virtuális mérete</translation> + </message> + <message> <source>Output index</source> <translation>Indeks izhoda</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(A tanúsítvány nem ellenőrzött)</translation> + </message> + <message> <source>Merchant</source> <translation>Kereskedő</translation> </message> @@ -2708,6 +3108,10 @@ <source>Label</source> <translation>Címke</translation> </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>%n további blokkra megnyitva</numerusform><numerusform>%n további blokkra megnyitva</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>%1 -ig megnyitva</translation> @@ -2977,12 +3381,28 @@ <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>A tárca hosszantartó bezárása nyesési üzemmódban azt eredményezheti, hogy a teljes láncot újra kell szinkronizálnia.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Összes tárca bezárása</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Biztos, hogy be akarod zárni az összes tárcát?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nincs betöltve pénztárca.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Nincs tárca megnyitva. +A Fájl > Megnyitás menüben lehet megnyitni. +- VAGY -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Új tárca készítése</translation> </message> </context> <context> @@ -2992,6 +3412,10 @@ <translation>Érmék Küldése</translation> </message> <message> + <source>Fee bump error</source> + <translation>Díj emelési hiba</translation> + </message> + <message> <source>Increasing transaction fee failed</source> <translation>Tranzakciós díj növelése sikertelen</translation> </message> @@ -3000,6 +3424,10 @@ <translation>Kívánja megnövelni a díjat?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Akarsz egy piszkozat tranzakciót díj emeléssel?</translation> + </message> + <message> <source>Current fee:</source> <translation>Jelenlegi díj:</translation> </message> @@ -3012,6 +3440,18 @@ <translation>Új díj:</translation> </message> <message> + <source>Confirm fee bump</source> + <translation>Erősitsd meg a díj emelését</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Sikertelen tranzakciós piszkozat</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT másolva</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Tranzakció aláírása sikertelen.</translation> </message> @@ -3035,6 +3475,30 @@ <translation>Jelenlegi nézet adatainak exportálása fájlba</translation> </message> <message> + <source>Error</source> + <translation>Hiba</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>PSBT sikertelen dekódolása a vágólapról (base64 érvénytelen)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Tranzakció adatainak betöltése</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Részlegesen Aláírt Tranzakció (PSBT bináris) (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>A PSBT fájlnak kisebbnek kell lennie mint 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>PSBT dekódolása sikertelen</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Biztonsági másolat készítése a Tárcáról</translation> </message> @@ -3058,7 +3522,11 @@ <source>The wallet data was successfully saved to %1.</source> <translation>A tárca adatai sikeresen elmentve %1.</translation> </message> - </context> + <message> + <source>Cancel</source> + <translation>Bezárás</translation> + </message> +</context> <context> <name>bitcoin-core</name> <message> @@ -3074,10 +3542,6 @@ <translation>Nyesés: az utolsó tárcaszinkronizálás meghaladja a nyesett adatokat. Szükséges a -reindex használata (nyesett csomópont esetében a teljes blokklánc ismételt letöltése).</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Hiba: Fatális belső hiba történt, nézze meg a debug.log -ot a részletekért</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Obrezujem ...</translation> </message> @@ -3094,14 +3558,34 @@ <translation>Az %s adatkönyvtár nem zárható. A %s valószínűleg fut már.</translation> </message> <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Nem lehetséges a megadott kapcsolatok és az addrman által felderített kapcsolatok egyidejű használata.</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>Hiba %s beolvasása közben. Az összes kulcs sikeresen beolvasva, de a tranzakciós adatok és a címtár rekordok hiányoznak vagy sérültek.</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>Opozorilo: Preverite, če sta datum in ura na vašem računalniku točna! %s ne bo deloval pravilno, če je nastavljeni čas nepravilen.</translation> </message> <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Kérlek támogasd ha hasznásnak találtad a %s-t. Az alábbi linken találsz bővebb információt a szoftverről %s.</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>A blokk adatbázis tartalmaz egy blokkot ami a jövőből érkezettnek látszik. Ennek oka lehet, hogy a számítógéped dátum és idő beállítása helytelen. Csak akkor építsd újra a block adatbázist ha biztos vagy benne, hogy az időbeállítás helyes.</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>Ez egy kiadás előtt álló, teszt verzió - csak saját felelősségre - ne használja bányászatra vagy kereskedéshez.</translation> </message> <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>Ezt a tranzakciós díjat figyelmen kívül hagyhatod ha a visszajáró kisebb mint a "porhintés" összege jelenleg.</translation> + </message> + <message> <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> <translation>Ne morem ponoviti blokov. Podatkovno bazo bo potrebno ponovno zgraditi z uporabo ukaza -reindex-chainstate.</translation> </message> @@ -3118,14 +3602,6 @@ <translation>Opozorilo: Trenutno se s soležniki ne strinjamo v popolnosti! Mogoče bi morali vi ali drugi udeleženci posodobiti odjemalce.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d od zadnjih 100 blokov imajo nepričakovano verzijo</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s poškodovana, obnova neuspešna</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool legalább %d MB kell legyen.</translation> </message> @@ -3138,6 +3614,10 @@ <translation>Indeks drobiža izven dovoljenega območja</translation> </message> <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>A konfigurációs beálltás %s kizárólag az %s hálózatra vonatkozik amikor a [%s] szekcióban van.</translation> + </message> + <message> <source>Copyright (C) %i-%i</source> <translation>Szerzői jog (C) fenntartva %i-%i</translation> </message> @@ -3146,6 +3626,14 @@ <translation>Sérült blokk-adatbázis észlelve</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>%s asmap fájl nem található</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>%s beolvasása sikertelen</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Újra akarod építeni a blokk adatbázist most?</translation> </message> @@ -3162,6 +3650,10 @@ <translation>Hiba a(z) %s betöltése közben</translation> </message> <message> + <source>Error loading %s: Private keys can only be disabled during creation</source> + <translation> %s betöltése sikertelen. A privát kulcsok csak a létrehozáskor tilthatóak le.</translation> + </message> + <message> <source>Error loading %s: Wallet corrupted</source> <translation>Hiba a(z) %s betöltése közben: A tárca hibás.</translation> </message> @@ -3194,6 +3686,14 @@ <translation>Helytelen vagy nemlétező genézis blokk. Helytelen hálózati adatkönyvtár?</translation> </message> <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>%s bezárása folyamatban. A kezdeti hibátlansági teszt sikertelen.</translation> + </message> + <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Érvénytelen P2P jog: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation>Neveljavna količina za -%s=<amount>: '%s'</translation> </message> @@ -3206,6 +3706,22 @@ <translation>Neveljavna količina za -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>A megadott blokk "%s" nem létezik.</translation> + </message> + <message> + <source>Unknown address type '%s'</source> + <translation>Ismeretlen cím típus '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Visszajáró típusa ismeretlen '%s'</translation> + </message> + <message> + <source>Upgrading txindex database</source> + <translation>txindex adatbázis frissítése</translation> + </message> + <message> <source>Loading P2P addresses...</source> <translation>P2P címek betöltése...</translation> </message> @@ -3246,10 +3762,22 @@ <translation>Na tem računalniku ni bilo mogoče vezati naslova %s. %s je verjetno že zagnan.</translation> </message> <message> + <source>Unable to generate keys</source> + <translation>Kulcs generálás sikertelen</translation> + </message> + <message> + <source>Unsupported logging category %s=%s.</source> + <translation>Nem támogatott logolási kategória %s=%s</translation> + </message> + <message> <source>Upgrading UTXO database</source> <translation>Blokk adatbázis frissítése</translation> </message> <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>Az ügyfélügynök megjegyzésben nem biztonságos karakter van: (%s) </translation> + </message> + <message> <source>Verifying blocks...</source> <translation>Blokkok ellenőrzése...</translation> </message> @@ -3262,10 +3790,50 @@ <translation>Napaka: Ni mogoče sprejemati dohodnih povezav (vrnjena napaka: %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s sérült. Megpróbálhatod a bitcoint-wallet tárcaj mentő eszközt, vagy mentésből helyreállítani a tárcát.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>A korábbi (nem HD) tárca nem frissíthető. Először frissíteni kell, hogy támogassa a "pre split keypool"-t. Használd a 169900 verziót vagy olyat amiben egyáltalán nincs verzió megadva.</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>Érvénytelen összeg -maxtxfee=<amount>: '%s' (legalább a minrelay összeg azaz %s kell legyen, hogy ne ragadjon be a tranzakció)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>A tranzakció összege túl alacsony az elküldéshez miután a díj levonódik</translation> + </message> + <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Ez a hiba akkor jelentkezhet ha a tárca nem volt rendesen lezárva és egy újabb verziójában volt megnyitva a Berkeley DB-nek. Ha így van akkor használd azt a verziót amivel legutóbb megnyitottad.</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Ez a maximum tranzakciós díj amit fizetni fogsz (a normál díj felett), hogy prioritizáld a részleges költés elkerülést a normál coin választás felett.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>A tranzakcióhoz szükség van egy visszajáró címre de nem tudtam létrehozni. Kérem először töltsd újra a címtárat a keypoolrefill paranccsal.</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>Újra kell építeni az adatbázist a -reindex használatával, ami a nyesett üzemmódot megszünteti. Ez a teljes blokklánc ismételt letöltésével jár.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Súlyos belső hiba történt, részletek a debug.log-ban</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>-peerblockfilters csak a -blockfilterindex -vel együtt állítható be.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Kevés a hely a lemezen!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Hiba az adatbázis olvasásakor, leállítás</translation> </message> @@ -3274,10 +3842,42 @@ <translation>Hiba a blokk adatbázis betöltése közben</translation> </message> <message> + <source>Error: Disk space is low for %s</source> + <translation>Hiba: kevés a hely a lemezen %s -nek!</translation> + </message> + <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>A címraktár kiürült, tötsd újra a keyppolrefill paranccsal.</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>A választott díj (%s) alacsonyabb mint a beállított minimum díj (%s)</translation> + </message> + <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Érvénytelen -onion cím vagy hostname: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Érvénytelen -proxy cím vagy hostname: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Érvénytelen tranzakciós díj -paytxfee=<amount>: '%s' (minimum ennyinek kell legyen %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Érvénytelen hálózati maszk van megadva itt: -whitelist: '%s'</translation> + </message> + <message> <source>Need to specify a port with -whitebind: '%s'</source> <translation>Pri opciji -whitebind morate navesti vrata: %s</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Proxy szerver nincs megadva. A megadás módja: -proxy=<ip> vagy -proxy=<ip:port></translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>A -blockfilterindex nem használható nyesés üzemmódban.</translation> </message> @@ -3286,6 +3886,10 @@ <translation>Zmanjšujem maksimalno število povezav (-maxconnections) iz %d na %d, zaradi sistemskih omejitev.</translation> </message> <message> + <source>Section [%s] is not recognized.</source> + <translation>Ismeretlen szekció [%s]</translation> + </message> + <message> <source>Signing transaction failed</source> <translation>Tranzakció aláírása sikertelen</translation> </message> @@ -3302,6 +3906,16 @@ <translation>A megadott "%s" -walletdir nem könyvtár</translation> </message> <message> + <source>The specified config file %s does not exist +</source> + <translation>A megadott konfigurációs fájl %s nem található. +</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>A tranzakció összege túl alacsony a tranzakciós költség kifizetéséhez.</translation> + </message> + <message> <source>This is experimental software.</source> <translation>Ez egy kísérleti szoftver.</translation> </message> @@ -3318,10 +3932,18 @@ <translation>Na tem računalniku ni bilo mogoče vezati naslova %s (vrnjena napaka: %s)</translation> </message> <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>PID fájl létrehozása sikertelen '%s': %s</translation> + </message> + <message> <source>Unable to generate initial keys</source> <translation>Ne zmorem ustvariti začetnih ključev</translation> </message> <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Ismeretlen -blockfilterindex érték %s.</translation> + </message> + <message> <source>Verifying wallet(s)...</source> <translation>Tárcák ellenőrzése...</translation> </message> @@ -3330,12 +3952,16 @@ <translation>Opozorilo: neznana nova pravila aktivirana (verzija %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>A tárca összes trancakciójának törlése...</translation> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee túl magasra van állítva! Ez a jelentős díj esetleg már egy egyszeri tranzakcióra is ki lehet fizetve.</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>Figyelem: A tárca-fájl megsérült, de az adatokat sikerült megmenteni! Az eredeti %s fájlt mentettük %s név alatt a %s könyvtárban. Amennyiben az egyenleg vagy a trancakciók helytelenek, állítsa vissza tárcáját a biztonsági mentés használatával.</translation> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>Ezt a tranzakciós díjat fogod fizetni ha a díjbecslés nem lehetséges.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>A hálózati verzió string (%i) hossza túllépi a megengedettet (%i). Csökkentsd a hosszt vagy a darabszámot uacomments beállításban.</translation> </message> <message> <source>%s is set very high!</source> @@ -3366,6 +3992,10 @@ <translation>Tranzakció összege nem lehet negatív</translation> </message> <message> + <source>Transaction has too long of a mempool chain</source> + <translation>A tranzakcóihoz tartozó mempool elődlánc túl hosszú</translation> + </message> + <message> <source>Transaction must have at least one recipient</source> <translation>Legalább egy címzett kell a tranzakcióhoz</translation> </message> @@ -3378,14 +4008,18 @@ <translation>Fedezethiány</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>A nem HD-s megosztott tárcát nem lehet bővíteni anélkül, hogy először a megosztás előtti kulcskészlet támogatására bővít. Használja az -upgradewallet=169900 parancsot vagy az -upgradewallet parancsot verzió megadása nélkül.</translation> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Díjbecslés sikertelen. Alapértelmezett díj le van tiltva. Fárj néhány blokkot vagy engedélyezd a -fallbackfee -t.</translation> </message> <message> <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> <translation>Figyelem: Privát kulcsokat észleltünk a {%s} tárcában, melynél a privát kulcsok le vannak tiltva.</translation> </message> <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Nem tudok írni a '%s' könyvtárba, ellenőrizd a jogosultságokat.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Blokkindex betöltése...</translation> </message> diff --git a/src/qt/locale/bitcoin_id.ts b/src/qt/locale/bitcoin_id.ts index e7be7825fc..51aafc98b8 100644 --- a/src/qt/locale/bitcoin_id.ts +++ b/src/qt/locale/bitcoin_id.ts @@ -70,10 +70,6 @@ <translation>Berikut ialah alamat-alamat Bitcoin Anda yang digunakan untuk mengirimkan pembayaran. Selalu periksa jumlah dan alamat penerima sebelum mengirimkan koin.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Ini adalah alamat Bitcoin untuk menerima pembayaran. Gunakan tombol 'Buat alamat penerima baru' di tab terima untuk membuat alamat baru.</translation> - </message> - <message> <source>&Copy Address</source> <translation>&Salin Alamat</translation> </message> @@ -482,6 +478,14 @@ <translation>Terbaru</translation> </message> <message> + <source>Node window</source> + <translation>Jendela Node</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Buka konsol debug dan diagnosa node</translation> + </message> + <message> <source>&Sending addresses</source> <translation>Address &Pengirim</translation> </message> @@ -490,6 +494,10 @@ <translation>Address &Penerima</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Buka URI bitcoin:</translation> + </message> + <message> <source>Open Wallet</source> <translation>Buka Wallet</translation> </message> @@ -617,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Dompet saat ini <b>terenkripsi</b> dan <b>terkunci</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Terjadi Kesalahan Fatal. Bitcoin Tidak Dapat Melanjutkan Dengan Aman Dan Akan Keluar</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -1050,6 +1054,14 @@ <translation>Sembunyikan</translation> </message> <message> + <source>Esc</source> + <translation>Keluar</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 menyinkronkan. Program ini akan mengunduh header dan blok dari rekan dan memvalidasi sampai blok terbaru.</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Tidak diketahui. Sinkronisasi Header (%1, %2%)...</translation> </message> @@ -1057,6 +1069,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Buka URI bitcoin:</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1115,10 +1131,6 @@ <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> @@ -1251,10 +1263,6 @@ <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> @@ -1429,7 +1437,18 @@ <source>Current total balance in watch-only addresses</source> <translation>Jumlah saldo di alamat hanya lihat</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Jumlah Keseluruhan</translation> + </message> + <message> + <source>or</source> + <translation>atau</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1449,6 +1468,10 @@ <translation>'bitcoin://' bukanlah alamat URI yang valid. Silakan gunakan 'bitcoin:'.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Tidak dapat memproses pembayaran karena dukungan BIP70 tidak disertakan.</translation> + </message> + <message> <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> <translation>Berhubung kelemahan keamanan yang meluas di BIP70, sangat disarankan agar instruksi pedagang untuk mengganti dompet diabaikan.</translation> </message> @@ -1689,10 +1712,6 @@ <translation>Rantai blok</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Jumlah blok terkini</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memory Pool</translation> </message> @@ -1737,10 +1756,6 @@ <translation>Pilih satu peer untuk melihat informasi detail.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Whitelist</translation> - </message> - <message> <source>Direction</source> <translation>Panduan</translation> </message> @@ -1761,12 +1776,24 @@ <translation>Block Yang Telah Sinkron</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Sistem Otonom yang dipetakan digunakan untuk mendiversifikasi pilihan peer</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>AS yang Dipetakan</translation> + </message> + <message> <source>User Agent</source> <translation>Agen Pengguna </translation> </message> <message> + <source>Node window</source> + <translation>Jendela Node</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>Buka file log debug %1 dari direktori data saat ini. Dapat memakan waktu beberapa detik untuk file log besar.</translation> </message> @@ -1783,10 +1810,6 @@ <translation>Layanan</translation> </message> <message> - <source>Ban Score</source> - <translation>Ban Score</translation> - </message> - <message> <source>Connection Time</source> <translation>Waktu Koneksi</translation> </message> @@ -1931,14 +1954,6 @@ <translation>keluar</translation> </message> <message> - <source>Yes</source> - <translation>Ya</translation> - </message> - <message> - <source>No</source> - <translation>Tidak</translation> - </message> - <message> <source>Unknown</source> <translation>Tidak diketahui</translation> </message> @@ -1974,6 +1989,14 @@ <translation>Nilai permintaan opsional. Biarkan ini kosong atau nol bila tidak meminta nilai tertentu.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Label fakultatif untuk menghubungkan dengan alamat penerima baru (anda menggunakannya untuk mengindetifikasi faktur). Itu juga dilampirkan pada permintaan pembayaran.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Pesan opsional yang dilampirkan di permintaan pembayaran dan dapat ditampilkan ke pengirim.</translation> + </message> + <message> <source>&Create new receiving address</source> <translation>&Create alamat penerima baru</translation> </message> @@ -2029,12 +2052,24 @@ <source>Copy amount</source> <translation>Salin Jumlah</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Tidak dapat membuka dompet.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Kode QR</translation> + <source>Amount:</source> + <translation>Nilai:</translation> + </message> + <message> + <source>Message:</source> + <translation>Pesan:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Wallet:</translation> </message> <message> <source>Copy &URI</source> @@ -2056,30 +2091,6 @@ <source>Payment information</source> <translation>Informasi pembayaran</translation> </message> - <message> - <source>URI</source> - <translation>Tautan</translation> - </message> - <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>Message</source> - <translation>Pesan</translation> - </message> - <message> - <source>Wallet</source> - <translation>Dompet</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2227,6 +2238,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Dust:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Sembunyikan pengaturan biaya transaksi</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Ketika volume transaksi lebih sedikit daripada ruang di blok, penambang serta simpul yang menyiarkanikan dapat memberlakukan biaya minimum. Anda boleh hanya membayar biaya minimum, tetapi perlu diketahui bahwa ini dapat menghasilkan transaksi yang tidak pernah dikonfirmasi setelah ada lebih banyak permintaan untuk transaksi bitcoin daripada yang dapat diproses jaringan.</translation> </message> @@ -2307,6 +2322,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>%1 ke %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Apakah anda ingin menjadikan transaksi ini sebagai konsep?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Apakah anda yakin ingin mengirimkan?</translation> </message> @@ -2343,6 +2362,18 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Konfirmasi pengiriman koin</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Konfirmasi proposal transaksi</translation> + </message> + <message> + <source>Send</source> + <translation>Kirim</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Saldo (hanya lihat):</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Alamat penerima tidak sesuai. Mohon periksa kembali.</translation> </message> @@ -2434,6 +2465,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Hapus masukan ini</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Jumlah yang ingin dikirim dalam unit yang dipilih</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>Biaya akan diambil dari jumlah yang dikirim. Penerima akan menerima bitcoin lebih sedikit daripada yang di masukkan di bidang jumlah. Jika ada beberapa penerima, biaya dibagi rata.</translation> </message> @@ -2556,6 +2591,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Alamat Bitcoin yang menandatangani pesan</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Pesan yang ditandatangani untuk diverifikasi</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Verifikasi pesan untuk memastikannya ditandatangani dengan alamat Bitcoin tersebut</translation> </message> @@ -2588,6 +2627,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Pembukaan kunci dompet dibatalkan.</translation> </message> <message> + <source>No error</source> + <translation>Tidak ada kesalahan</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Private key untuk alamat yang dimasukkan tidak tersedia.</translation> </message> @@ -2638,10 +2681,22 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Buka sampai %1</translation> </message> <message> + <source>conflicted with a transaction with %1 confirmations</source> + <translation>Konflik dengan sebuah transaksi dengan %1 konfirmasi</translation> + </message> + <message> <source>0/unconfirmed, %1</source> <translation>0/belum dikonfirmasi, %1</translation> </message> <message> + <source>in memory pool</source> + <translation>Dalam pool memory</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>Tidak dalam pool memory</translation> + </message> + <message> <source>%1/unconfirmed</source> <translation>%1/belum dikonfirmasi</translation> </message> @@ -2662,10 +2717,30 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Sumber</translation> </message> <message> + <source>Generated</source> + <translation>Dihasilkan</translation> + </message> + <message> + <source>From</source> + <translation>Dari</translation> + </message> + <message> <source>unknown</source> <translation>tidak diketahui</translation> </message> <message> + <source>To</source> + <translation>Untuk</translation> + </message> + <message> + <source>own address</source> + <translation>alamat milik sendiri</translation> + </message> + <message> + <source>watch-only</source> + <translation>hanya-melihat</translation> + </message> + <message> <source>label</source> <translation>label</translation> </message> @@ -2694,6 +2769,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Biaya Transaksi</translation> </message> <message> + <source>Net amount</source> + <translation>Jumlah bersih</translation> + </message> + <message> <source>Message</source> <translation>Pesan</translation> </message> @@ -2706,6 +2785,26 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>ID Transaksi</translation> </message> <message> + <source>Transaction total size</source> + <translation>Ukuran transaksi total</translation> + </message> + <message> + <source>Transaction virtual size</source> + <translation>Ukuran transaksi virtual</translation> + </message> + <message> + <source>Output index</source> + <translation>Indeks outpu</translation> + </message> + <message> + <source> (Certificate was not verified)</source> + <translation>(Sertifikat tidak diverifikasi)</translation> + </message> + <message> + <source>Merchant</source> + <translation>Penjual</translation> + </message> + <message> <source>Debug information</source> <translation>Informasi debug</translation> </message> @@ -2714,6 +2813,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Transaksi</translation> </message> <message> + <source>Inputs</source> + <translation>Input</translation> + </message> + <message> <source>Amount</source> <translation>Jumlah</translation> </message> @@ -2751,6 +2854,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <source>Label</source> <translation>Label</translation> </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Buka %n untuk blok lebih</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Buka sampai %1</translation> @@ -2760,6 +2867,22 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Belum dikonfirmasi</translation> </message> <message> + <source>Abandoned</source> + <translation>yang ditelantarkan</translation> + </message> + <message> + <source>Confirmed (%1 confirmations)</source> + <translation>Dikonfirmasi (%1 konfirmasi)</translation> + </message> + <message> + <source>Conflicted</source> + <translation>Bertentangan</translation> + </message> + <message> + <source>Generated but not accepted</source> + <translation>Dihasilkan tapi tidak diterima</translation> + </message> + <message> <source>Received with</source> <translation>Diterima dengan</translation> </message> @@ -2772,10 +2895,26 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Dikirim ke</translation> </message> <message> + <source>Payment to yourself</source> + <translation>Pembayaran untuk diri sendiri</translation> + </message> + <message> + <source>Mined</source> + <translation>Ditambang</translation> + </message> + <message> + <source>watch-only</source> + <translation>hanya-melihat</translation> + </message> + <message> <source>(no label)</source> <translation>(tidak ada label)</translation> </message> <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation>Status transaksi. Arahkan kursor ke bidang ini untuk menampilkan jumlah konfirmasi.</translation> + </message> + <message> <source>Date and time that the transaction was received.</source> <translation>Tanggal dan waktu transaksi telah diterima.</translation> </message> @@ -2783,7 +2922,19 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <source>Type of transaction.</source> <translation>Tipe transaksi.</translation> </message> - </context> + <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Apakah alamat hanya-melihat terlibat dalam transaksi ini atau tidak.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>maksud/tujuan transaksi yang ditentukan pengguna.</translation> + </message> + <message> + <source>Amount removed from or added to balance.</source> + <translation>Jumlah dihapus dari atau ditambahkan ke saldo.</translation> + </message> +</context> <context> <name>TransactionView</name> <message> @@ -2811,6 +2962,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Tahun ini</translation> </message> <message> + <source>Range...</source> + <translation>Jarak...</translation> + </message> + <message> <source>Received with</source> <translation>Diterima dengan</translation> </message> @@ -2819,6 +2974,14 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Dikirim ke</translation> </message> <message> + <source>To yourself</source> + <translation>Untuk diri sendiri</translation> + </message> + <message> + <source>Mined</source> + <translation>Ditambang</translation> + </message> + <message> <source>Other</source> <translation>Lainnya</translation> </message> @@ -2855,6 +3018,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Salain ID Transaksi</translation> </message> <message> + <source>Copy raw transaction</source> + <translation>Salin transaksi yang belum diproses</translation> + </message> + <message> <source>Copy full transaction details</source> <translation>Salin detail transaksi</translation> </message> @@ -2879,6 +3046,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Terkonfirmasi</translation> </message> <message> + <source>Watch-only</source> + <translation>Hanya-melihat</translation> + </message> + <message> <source>Date</source> <translation>Tanggal</translation> </message> @@ -2903,23 +3074,55 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Mengekspor Gagal</translation> </message> <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation>Terjadi kesalahan saat mencoba menyimpan riwayat transaksi ke %1.</translation> + </message> + <message> <source>Exporting Successful</source> <translation>Ekspor Berhasil</translation> </message> - </context> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>Riwayat transaksi berhasil disimpan ke %1.</translation> + </message> + <message> + <source>Range:</source> + <translation>Jarak:</translation> + </message> + <message> + <source>to</source> + <translation>untuk</translation> + </message> +</context> <context> <name>UnitDisplayStatusBarControl</name> - </context> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Unit untuk menunjukkan jumlah. Klik untuk memilih unit lain.</translation> + </message> +</context> <context> <name>WalletController</name> <message> <source>Close wallet</source> <translation>Tutup wallet</translation> </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Apakah anda yakin ingin menutup dompet <i>%1</i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Menutup dompet terlalu lama dapat menyebabkan harus menyinkron ulang seluruh rantai jika pemangkasan diaktifkan.</translation> + </message> </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Bikin dompet baru</translation> + </message> +</context> <context> <name>WalletModel</name> <message> @@ -2927,6 +3130,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Kirim Koin</translation> </message> <message> + <source>Fee bump error</source> + <translation>Kesalahan biaya tagihan</translation> + </message> + <message> <source>Increasing transaction fee failed</source> <translation>Gagal meningkatkan biaya transaksi</translation> </message> @@ -2935,6 +3142,10 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Apa Anda ingin meningkatkan biayanya?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Apakah anda ingin membuat draf transaksi dengan kenaikan biaya?</translation> + </message> + <message> <source>Current fee:</source> <translation>Biaya saat ini:</translation> </message> @@ -2947,6 +3158,26 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Biaya baru:</translation> </message> <message> + <source>Confirm fee bump</source> + <translation>Konfirmasi biaya tambahan</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Tidak dapat membuat konsep transaksi.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT disalin</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Tidak dapat menandatangani transaksi.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Tidak dapat melakukan transaksi</translation> + </message> + <message> <source>default wallet</source> <translation>wallet default</translation> </message> @@ -2962,14 +3193,34 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Ekspor data dalam tab sekarang ke sebuah berkas</translation> </message> <message> + <source>Error</source> + <translation>Kesalahan</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>Cadangkan Dompet</translation> + </message> + <message> + <source>Wallet Data (*.dat)</source> + <translation>Data Dompet (*.dat)</translation> + </message> + <message> <source>Backup Failed</source> <translation>Pencadangan Gagal</translation> </message> <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation>Terjadi kesalahan saat mencoba menyimpan data dompet ke %1.</translation> + </message> + <message> <source>Backup Successful</source> <translation>Pencadangan Berhasil</translation> </message> <message> + <source>The wallet data was successfully saved to %1.</source> + <translation>Data dompet berhasil disimpan ke %1.</translation> + </message> + <message> <source>Cancel</source> <translation>Batal</translation> </message> @@ -2977,6 +3228,62 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <context> <name>bitcoin-core</name> <message> + <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> + <translation>Didistribusikan di bawah lisensi perangkat lunak MIT, lihat berkas terlampir %s atau %s</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Pemangkasan dikonfigurasikan di bawah minimum dari %d MiB. Harap gunakan angka yang lebih tinggi.</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>Pemangkasan: sinkronisasi dompet terakhir melampaui data yang sudah dipangkas. Anda perlu -reindex (unduh seluruh blockchain lagi jika terjadi node pemangkasan)</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Memangkas blockstore...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Tidak dapat memulai server HTTP. Lihat log debug untuk detailnya.</translation> + </message> + <message> + <source>The %s developers</source> + <translation>Pengembang %s</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Tidak dapat memperoleh kunci pada direktori data %s. %s mungkin sudah berjalan.</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>Kesalahan membaca %s! Semua kunci dibaca dengan benar, tetapi data transaksi atau entri buku alamat mungkin hilang atau salah.</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>Periksa apakah tanggal dan waktu komputer anda benar! Jika jam anda salah, %s tidak akan berfungsi dengan baik.</translation> + </message> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Silakan berkontribusi jika %s berguna. Kunjungi %s untuk informasi lebih lanjut tentang perangkat lunak.</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>Blok basis data berisi blok yang tampaknya berasal dari masa depan. Ini mungkin karena tanggal dan waktu komputer anda diatur secara tidak benar. Bangun kembali blok basis data jika anda yakin tanggal dan waktu komputer anda benar</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>Ini adalah uji coba pra-rilis - gunakan dengan risiko anda sendiri - jangan digunakan untuk aplikasi penambangan atau penjual</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Peringatan: Jaringan tampaknya tidak sepenuhnya setuju! Beberapa penambang tampaknya mengalami masalah.</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>Peringatan: Kami tampaknya tidak sepenuhnya setuju dengan peers kami! Anda mungkin perlu memutakhirkan, atau nodes lain mungkin perlu dimutakhirkan.</translation> + </message> + <message> <source>Corrupted block database detected</source> <translation>Menemukan database blok yang rusak</translation> </message> @@ -3009,26 +3316,124 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Tidak bisa cari blok pertama, atau blok pertama salah. Salah direktori untuk jaringan?</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Eror: Kapasitas penyimpanan penuh!</translation> + <source>Loading P2P addresses...</source> + <translation>Memuat alamat P2P....</translation> + </message> + <message> + <source>Loading banlist...</source> + <translation>Memuat banlist...</translation> </message> <message> <source>Not enough file descriptors available.</source> <translation>Deskripsi berkas tidak tersedia dengan cukup.</translation> </message> <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Pemangkasan tidak dapat dikonfigurasi dengan nilai negatif.</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>Kode sumber tersedia dari %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <translation>Biaya transaksi dan kalkulasi perubahan gagal</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <translation>Tidak dapat mengikat ke %s di komputer ini. %s mungkin sudah berjalan.</translation> + </message> + <message> + <source>Unable to generate keys</source> + <translation>Tidak dapat menghasilkan kunci</translation> + </message> + <message> + <source>Unsupported logging category %s=%s.</source> + <translation>Kategori logging yang tidak didukung %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Memutakhirkan basis data UTXO</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>Komentar Agen Pengguna (%s) berisi karakter yang tidak aman.</translation> + </message> + <message> <source>Verifying blocks...</source> <translation>Blok-blok sedang diverifikasi...</translation> </message> <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Dompet harus ditulis ulang: mulai ulang %s untuk menyelesaikan</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Error: Mendengarkan koneksi yang masuk gagal (dengarkan kesalahan yang dikembalikan %s)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>Jumlah transaksi terlalu kecil untuk dikirim setelah biaya dikurangi</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>Anda perlu membangun kembali basis data menggunakan -reindex untuk kembali ke mode tidak dipangkas. Ini akan mengunduh ulang seluruh blockchain</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Kesalahan membaca dari basis data, mematikan.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Kesalahan memutakhirkan basis data chainstate</translation> + </message> + <message> <source>Error: Disk space is low for %s</source> <translation>Eror: Kapasitas penyimpanan penuh untuk %s</translation> </message> <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Alamat -onion atau hostname tidak valid: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Alamat proxy atau hostname tidak valid: '%s'</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Netmask tidak valid yang ditentukan di -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Perlu menentukan port dengan -whitebind: '%s'</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Mode pemangkasan tidak kompatibel dengan -blockfilterindex.</translation> + </message> + <message> + <source>Section [%s] is not recognized.</source> + <translation>Bagian [%s] tidak dikenali.</translation> + </message> + <message> <source>Signing transaction failed</source> <translation>Tandatangani transaksi tergagal</translation> </message> <message> + <source>The specified config file %s does not exist +</source> + <translation>Berkas konfigurasi %s yang ditentukan tidak ada +</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>Jumlah transaksi terlalu kecil untuk membayar biaya ongkos</translation> + </message> + <message> + <source>This is experimental software.</source> + <translation>Ini adalah perangkat lunak eksperimental.</translation> + </message> + <message> <source>Transaction amount too small</source> <translation>Nilai transaksi terlalu kecil</translation> </message> @@ -3037,8 +3442,40 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Transaksi terlalu besar</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Setiap transaksi dalam dompet sedang di-'Zap'...</translation> + <source>Verifying wallet(s)...</source> + <translation>Memverifikasi dompet...</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s diset sangat tinggi!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Terjadi kesalahan saat memuat dompet %s duplikat -wallet nama file yang diterapkan</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>Dompet akan menghindari pembayaran kurang dari biaya minimum ongkos relay.</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>Ini adalah ongkos transaksi minimum yang anda bayarkan untuk setiap transaksi.</translation> + </message> + <message> + <source>This is the transaction fee you will pay if you send a transaction.</source> + <translation>Ini adalah ongkos transaksi yang akan anda bayarkan jika anda mengirim transaksi.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <translation>Jumlah transaksi tidak boleh negatif</translation> + </message> + <message> + <source>Transaction has too long of a mempool chain</source> + <translation>Transaksi mempunyai rantai mempool yang terlalu panjang</translation> + </message> + <message> + <source>Transaction must have at least one recipient</source> + <translation>Transaksi harus mempunyai paling tidak satu penerima</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> @@ -3049,6 +3486,14 @@ Catatan: Karena biaya dihitung berdasarkan per byte, biaya "100 satoshi per kB" <translation>Saldo tidak mencukupi</translation> </message> <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Peringatan: Kunci pribadi terdeteksi di dompet {%s} dengan kunci pribadi yang dinonaktifkan</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Tidak dapat menulis ke direktori data '%s'; periksa izinnya.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Memuat indeks blok...</translation> </message> diff --git a/src/qt/locale/bitcoin_is.ts b/src/qt/locale/bitcoin_is.ts index 6eb5c10107..61e9078e1e 100644 --- a/src/qt/locale/bitcoin_is.ts +++ b/src/qt/locale/bitcoin_is.ts @@ -168,6 +168,10 @@ <translation>Veski dulkóðað</translation> </message> <message> + <source>Wallet to be encrypted</source> + <translation>Veski sem á að dulkóða</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> @@ -491,11 +495,7 @@ <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> <context> <name>CoinControlDialog</name> <message> @@ -691,7 +691,10 @@ <source>Current total balance in watch-only addresses</source> <translation>Innistæða á færslugildum sem eru einungis til skoðunar</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + </context> <context> <name>PaymentServer</name> <message> @@ -723,10 +726,6 @@ <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> @@ -757,22 +756,10 @@ <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> + <source>Amount:</source> + <translation>Upphæð:</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -921,6 +908,10 @@ <source>Export the data in the current tab to a file</source> <translation>Flytja gögn í flipanum í skrá</translation> </message> + <message> + <source>Error</source> + <translation>Villa</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts index 2cd0941a8c..80131e5b42 100644 --- a/src/qt/locale/bitcoin_it.ts +++ b/src/qt/locale/bitcoin_it.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Fai clic con il tasto destro del mouse per modificare l'indirizzo o l'etichetta</translation> + <translation>Fai clic con il tasto destro del mouse per modificare l'indirizzo oppure l'etichetta</translation> </message> <message> <source>Create a new address</source> @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Copia negli appunti l'indirizzo attualmente selezionato</translation> + <translation>Copia negli appunti del sistema l'indirizzo attualmente selezionato</translation> </message> <message> <source>&Copy</source> @@ -70,8 +70,10 @@ <translation>Questi sono i tuoi indirizzi Bitcoin per l'invio di pagamenti. Controlla sempre l'importo e l'indirizzo del beneficiario prima di inviare bitcoin.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Usa il tasto "Crea nuovo indirizzo ricevente" nella schermata "Ricevi" per creare nuovi indirizzi.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Questi sono i tuoi indirizzi Bitcoin per ricevere pagamenti. Usa il tasto "Crea nuovo indirizzo ricevente" nella schermata "Ricevi" per creare nuovi indirizzi. +E' possibile firmare solo con indirizzi di tipo "legacy".</translation> </message> <message> <source>&Copy Address</source> @@ -87,11 +89,11 @@ </message> <message> <source>Export Address List</source> - <translation>Esporta elenco indirizzi</translation> + <translation>Esporta elenco degli indirizzi</translation> </message> <message> <source>Comma separated file (*.csv)</source> - <translation>Testo CSV (*.csv)</translation> + <translation>File diviso da virgole (*.csv)</translation> </message> <message> <source>Exporting Failed</source> @@ -169,7 +171,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>Attenzione: Se si cifra il portamonete e si perde la passphrase <b>TUTTI I PROPRI BITCOIN ANDRANNO PERSI</b>!</translation> + <translation>Attenzione: Se si cifra il portafoglio e si perde la passphrase <b>TUTTI I PROPRI BITCOIN ANDRANNO PERSI</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> @@ -482,6 +484,22 @@ <translation>Aggiornato</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Carica PSBT da file...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Carica Partially Signed Bitcoin Transaction</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Carica PSBT dagli appunti...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Carica Partially Signed Bitcoin Transaction dagli appunti</translation> + </message> + <message> <source>Node window</source> <translation>Finestra del nodo</translation> </message> @@ -518,10 +536,26 @@ <translation>Chiudi il portafoglio</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Chiudi Tutti i Portafogli...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Chiudi tutti i portafogli</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Mostra il messaggio di aiuto di %1 per ottenere una lista di opzioni di comando per Bitcoin</translation> </message> <message> + <source>&Mask values</source> + <translation>&Valori della maschera</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Maschera i valori nella sezione "Panoramica"</translation> + </message> + <message> <source>default wallet</source> <translation>Portafoglio predefinito:</translation> </message> @@ -630,8 +664,12 @@ <translation>Il portamonete è <b>cifrato</b> ed attualmente <b>bloccato</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Si è verificato un errore critico. Bitcoin non può più funzionare in maniera sicura e verrà chiuso.</translation> + <source>Original message:</source> + <translation>Messaggio originale:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Si è verificato un errore critico. %1 non può più continuare in maniera sicura e verrà chiuso.</translation> </message> </context> <context> @@ -835,6 +873,14 @@ <translation>Crea Portafoglio Vuoto</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Usa descriptors per gestione scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Descrizione del Portafoglio</translation> + </message> + <message> <source>Create</source> <translation>Crea</translation> </message> @@ -1139,10 +1185,6 @@ <translation>Mostra se il proxy SOCK5 di default che p stato fornito è usato per raggiungere i contatti attraverso questo tipo di rete.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Usa una SOCKS&5 proxy differente per raggiungere peers usando servizi Tor hidden</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Nascondi l'icona nella barra delle applicazioni.</translation> </message> @@ -1276,10 +1318,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Connette alla rete Bitcoin attraverso un proxy SOCKS5 separato per Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Finestra</translation> </message> @@ -1320,6 +1358,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Specifica se le funzionalita di coin control saranno visualizzate.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Connette alla rete Bitcoin attraverso un proxy SOCKS5 separato per i Tor onion services.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Usa un proxy SOCKS&5 separato per raggiungere peers attraverso i Tor onion services.</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&URL di terze parti per transazioni</translation> </message> @@ -1454,6 +1500,133 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <source>Current total balance in watch-only addresses</source> <translation>Saldo corrente totale negli indirizzi di sola lettura</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Modalità privacy attivata per la scheda "Panoramica". Per smascherare i valori, deseleziona Impostazioni-> Valori maschera.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialogo</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Firma Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Trasmetti Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Copia negli Appunti</translation> + </message> + <message> + <source>Save...</source> + <translation>Salva...</translation> + </message> + <message> + <source>Close</source> + <translation>Chiudi</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Caricamento della transazione fallito: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Firma della transazione fallita: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Non posso firmare piu' inputs.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Firmato %1 inputs, ma sono richieste piu' firme.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Transazione firmata con successo. La transazione é pronta per essere trasmessa.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Errore sconosciuto processando la transazione.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Transazione trasmessa con successo! ID della transazione: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Trasmissione della transazione fallita: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT copiata negli appunti.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Salva Dati Transazione</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transazione Parzialmente Firmata (Binario) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT salvata su disco.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation> * Invia %1 a %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Non in grado di calcolare la fee della transazione o l'ammontare totale della transazione.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Paga fee della transazione: </translation> + </message> + <message> + <source>Total Amount</source> + <translation>Importo totale</translation> + </message> + <message> + <source>or</source> + <translation>o</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>La transazione ha %1 inputs non firmati.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>La transazione manca di alcune informazioni sugli inputs.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>La transazione necessita ancora di firma/e.</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Ma questo portafoglio non può firmare transazioni.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Ma questo portafoglio non ha le chiavi giuste.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>La transazione è completamente firmata e pronta per essere trasmessa.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Lo stato della transazione è sconosciuto.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1620,6 +1793,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Errore: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Errore durante l'inizializzazione delle impostazioni: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 non è ancora stato chiuso in modo sicuro</translation> </message> @@ -1718,10 +1895,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Block chain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Numero attuale di blocchi</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memory Pool</translation> </message> @@ -1766,10 +1939,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Seleziona un peer per visualizzare informazioni più dettagliate.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Whitelisted/sicuri</translation> - </message> - <message> <source>Direction</source> <translation>Direzione</translation> </message> @@ -1790,6 +1959,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Blocchi sincronizzati</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Il Sistema Autonomo mappato utilizzato per diversificare la selezione dei peer.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>AS mappato</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> @@ -1798,6 +1975,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Finestra del nodo</translation> </message> <message> + <source>Current block height</source> + <translation>Altezza del blocco corrente</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>Apri il file log del debug di %1 dalla cartella dati attuale. Può richiedere alcuni secondi per file di log di grandi dimensioni.</translation> </message> @@ -1810,12 +1991,12 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>Aumenta dimensioni font</translation> </message> <message> - <source>Services</source> - <translation>Servizi</translation> + <source>Permissions</source> + <translation>Permessi</translation> </message> <message> - <source>Ban Score</source> - <translation>Punteggio di Ban</translation> + <source>Services</source> + <translation>Servizi</translation> </message> <message> <source>Connection Time</source> @@ -1966,14 +2147,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <translation>In uscita</translation> </message> <message> - <source>Yes</source> - <translation>Si</translation> - </message> - <message> - <source>No</source> - <translation>No</translation> - </message> - <message> <source>Unknown</source> <translation>Sconosciuto</translation> </message> @@ -2072,56 +2245,60 @@ Per specificare più URL separarli con una barra verticale "|".</translation> <source>Copy amount</source> <translation>Copia l'importo</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Impossibile sbloccare il portafoglio.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Non è stato possibile generare il nuovo %1 indirizzo</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Codice QR</translation> - </message> - <message> - <source>Copy &URI</source> - <translation>Copia &URI</translation> + <source>Request payment to ...</source> + <translation>Richiedi pagamento a ...</translation> </message> <message> - <source>Copy &Address</source> - <translation>Copia &Indirizzo</translation> + <source>Address:</source> + <translation>Indirizzo:</translation> </message> <message> - <source>&Save Image...</source> - <translation>&Salva Immagine...</translation> + <source>Amount:</source> + <translation>Importo:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Richiesta di pagamento a %1</translation> + <source>Label:</source> + <translation>Etichetta:</translation> </message> <message> - <source>Payment information</source> - <translation>Informazioni di pagamento</translation> + <source>Message:</source> + <translation>Messaggio:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Portafoglio:</translation> </message> <message> - <source>Address</source> - <translation>Indirizzo</translation> + <source>Copy &URI</source> + <translation>Copia &URI</translation> </message> <message> - <source>Amount</source> - <translation>Importo</translation> + <source>Copy &Address</source> + <translation>Copia &Indirizzo</translation> </message> <message> - <source>Label</source> - <translation>Etichetta</translation> + <source>&Save Image...</source> + <translation>&Salva Immagine...</translation> </message> <message> - <source>Message</source> - <translation>Messaggio</translation> + <source>Request payment to %1</source> + <translation>Richiesta di pagamento a %1</translation> </message> <message> - <source>Wallet</source> - <translation>Portafoglio</translation> + <source>Payment information</source> + <translation>Informazioni di pagamento</translation> </message> </context> <context> @@ -2370,8 +2547,20 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Sei sicuro di voler inviare?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Per favore, rivedi la tua proposta di transazione. Questo produrrà una Transazione Bitcoin Parzialmente Firmata (PSBT) che puoi copiare e quindi firmare con es. un portafoglio %1 offline o un portafoglio hardware compatibile con PSBT.</translation> + <source>Create Unsigned</source> + <translation>Crea non Firmata</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Salva Dati Transazione</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transazione Parzialmente Firmata (Binario) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT salvata</translation> </message> <message> <source>or</source> @@ -2382,6 +2571,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Si puó aumentare la commissione successivamente (segnalando Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Per favore, controlla la tua proposta di transazione. Questo produrrà una Partially Signed Bitcoin Transaction (PSBT) che puoi salvare o copiare e quindi firmare con es. un portafoglio %1 offline o un portafoglio hardware compatibile con PSBT.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Per favore, rivedi la tua transazione.</translation> </message> @@ -2410,18 +2603,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Conferma la proposta di transazione</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Copia PSBT negli appunti</translation> - </message> - <message> <source>Send</source> <translation>Invia</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT copiata</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Saldo watch-only</translation> </message> @@ -3203,12 +3388,28 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Chiudere il portafoglio per troppo tempo può causare la resincronizzazione dell'intera catena se la modalità "pruning" è attiva.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Chiudi tutti i portafogli</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Sei sicuro di voler chiudere tutti i portafogli?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Non è stato caricato alcun portafoglio.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Nessun portafoglio è stato caricato. +Vai su File > Apri Portafoglio per caricare un portafoglio. +- OR -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crea un nuovo portafoglio</translation> </message> </context> <context> @@ -3281,6 +3482,30 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Esporta su file i dati contenuti nella tabella corrente</translation> </message> <message> + <source>Error</source> + <translation>Errore</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Non in grado di decodificare PSBT dagli appunti (base64 non valida)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Carica Dati Transazione</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Transazione Parzialmente Firmata (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>Il file PSBT deve essere inferiore a 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Non in grado di decodificare PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Backup Portafoglio</translation> </message> @@ -3324,10 +3549,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Prune: l'ultima sincronizzazione del portafoglio risulta essere precedente alla eliminazione dei dati per via della modalità "pruning". È necessario eseguire un -reindex (scaricare nuovamente la blockchain in caso di nodo pruned).</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Errore: si è presentato un errore interno fatale, consulta il file debug.log per maggiori dettagli</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Pruning del blockstore...</translation> </message> @@ -3340,10 +3561,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Sviluppatori di %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Impossibile generare una chiave per il resto. Non c'è nessuna chiave nel keypool interno ed è impossibile generare altre chiavi.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Non è possibile ottenere i dati sulla cartella %s. Probabilmente %s è già in esecuzione.</translation> </message> @@ -3356,6 +3573,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>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation>Viene fornito più di un indirizzo di associazione onion. L'utilizzo di %s per il servizio Tor onion viene creato automaticamente.</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> @@ -3392,14 +3613,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Attenzione: Sembra che non vi sia pieno consenso con i nostri peer! Un aggiornamento da parte tua o degli altri nodi potrebbe essere necessario.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d degli ultimi 100 blocchi hanno una versione inaspettata</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrotto, recupero fallito</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool deve essere almeno %d MB</translation> </message> @@ -3476,6 +3689,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Impossibile ripetere la scansione del portafoglio durante l'inizializzazione</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Errore nella verifica del database</translation> + </message> + <message> <source>Importing...</source> <translation>Importazione...</translation> </message> @@ -3504,6 +3721,22 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Importo non valido per -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase: Errore nell'eseguire l'operazione di verifica del database: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase: Errore nel verificare il database: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase: Errore nella lettura della verifica del database: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase: Application id non riconosciuto. Mi aspetto un %u, arriva un %u</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation>La cartella specificata "%s" non esiste.</translation> </message> @@ -3524,10 +3757,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Caricamento indirizzi P2P...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Errore: Spazio su disco insufficiente!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Caricamento bloccati...</translation> </message> @@ -3592,6 +3821,14 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Errore: attesa per connessioni in arrivo fallita (errore riportato %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s corrotto. Prova a usare la funzione del portafoglio bitcoin-wallet per salvare o recuperare il backup</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Impossibile aggiornare un portafoglio diviso non HD senza aggiornamento per supportare il keypool pre-split. Si prega di utilizzare -upgradewallet = 169900 o -upgradewallet senza specificare la versione.</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>Importo non valido per -maxtxfee=<amount>: '%s' (deve essere almeno pari alla commissione 'minrelay fee' di %s per prevenire transazioni bloccate)</translation> </message> @@ -3600,10 +3837,30 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>L'importo della transazione risulta troppo basso per l'invio una volta dedotte le commissioni.</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Questo errore potrebbe essersi verificato se questo portafoglio non è stato chiuso in modo pulito ed è stato caricato l'ultima volta utilizzando una build con una versione più recente di Berkeley DB. In tal caso, utilizza il software che ha caricato per ultimo questo portafoglio</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>La transazione richiede un indirizzo di resto, ma non possiamo generarlo. Si prega di eseguire prima keypoolrefill.</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>Per ritornare alla modalità unpruned sarà necessario ricostruire il database utilizzando l'opzione -reindex. L'intera blockchain sarà riscaricata.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Si è verificato un errore interno fatale, consultare debug.log per i dettagli</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Non e' possibile impostare -peerblockfilters senza -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Lo spazio su disco è insufficiente!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Errore durante la lettura del database. Arresto in corso.</translation> </message> @@ -3616,6 +3873,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Errore: lo spazio sul disco è troppo poco per %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Errore: Keypool esaurito, esegui prima keypoolrefill</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Indirizzo -onion o hostname non valido: '%s'</translation> </message> @@ -3636,6 +3897,10 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>È necessario specificare una porta con -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Nessun server proxy specificato. Usa -proxy=<ip> o -proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>La modalità ridotta(pruned) non è compatibile con -blockfilterindex</translation> </message> @@ -3710,10 +3975,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Attenzione: nuove regole non conosciute attivate (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Eliminazione dal portafoglio di tutte le transazioni...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee è impostato molto alto! Commissioni così alte possono venir pagate anche su una singola transazione.</translation> </message> @@ -3726,10 +3987,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>La lunghezza totale della stringa di network version (%i) eccede la lunghezza massima (%i). Ridurre il numero o la dimensione di uacomments.</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>Attenzione: file del Portafoglio corrotto, dati recuperati! %s originale salvato come %s in %s; se il saldo o le transazioni non sono corrette effettua un ripristino da un backup.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s ha un'impostazione molto alta!</translation> </message> @@ -3774,10 +4031,6 @@ Nota: poiché la commissione è calcolata su base per byte, una commissione di " <translation>Fondi insufficienti</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>Impossibile aggiornare un portafoglio diviso non HD senza aggiornamento per supportare il keypool pre-split. Si prega di utilizzare -upgradewallet = 169900 o -upgradewallet senza specificare la versione.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Stima della commissione non riuscita. Fallbackfee è disabilitato. Attendi qualche blocco o abilita -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts index ea1bf17838..ccbc135c16 100644 --- a/src/qt/locale/bitcoin_ja.ts +++ b/src/qt/locale/bitcoin_ja.ts @@ -67,11 +67,7 @@ </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> - </message> - <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>これらは支払いを受け取るための、あなたの Bitcoin アドレスです。新しいアドレスを作成するには受取タブ内の「新しい受取用アドレスを作成」ボタンを使用します。</translation> + <translation>これらは、あなたが知っている送信先の Bitcoin アドレスです。コインを送る前に必ず、金額と受取用アドレスを確認してください。</translation> </message> <message> <source>&Copy Address</source> @@ -91,7 +87,7 @@ </message> <message> <source>Comma separated file (*.csv)</source> - <translation>テキスト CSV (*.csv)</translation> + <translation>CSVファイル (*.csv)</translation> </message> <message> <source>Exporting Failed</source> @@ -114,7 +110,7 @@ </message> <message> <source>(no label)</source> - <translation>(ラベル無し)</translation> + <translation>(ラベル無し)</translation> </message> </context> <context> @@ -133,7 +129,7 @@ </message> <message> <source>Repeat new passphrase</source> - <translation>新しいパスフレーズをもう一度</translation> + <translation>新しいパスフレーズをもう一度入力</translation> </message> <message> <source>Show passphrase</source> @@ -169,7 +165,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> @@ -206,7 +202,7 @@ </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> @@ -392,7 +388,7 @@ </message> <message> <source>Show or hide the main Window</source> - <translation>メイン ウインドウを表示または非表示する</translation> + <translation>メインウィンドウを表示または非表示にする</translation> </message> <message> <source>Encrypt the private keys that belong to your wallet</source> @@ -400,7 +396,7 @@ </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> @@ -424,7 +420,7 @@ </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> @@ -483,6 +479,18 @@ <translation>ブロックは最新</translation> </message> <message> + <source>Load PSBT from clipboard...</source> + <translation>PSBTをクリップボードから読み込み</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>部分的に署名されたビットコインのトランザクションをクリップボードから読み込み</translation> + </message> + <message> + <source>Node window</source> + <translation>ノードウィンドウ</translation> + </message> + <message> <source>Open node debugging and diagnostic console</source> <translation>ノードのデバッグ・診断コンソールを開く</translation> </message> @@ -515,8 +523,16 @@ <translation>ウォレットを閉じる</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>全てのウォレットを閉じる</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>全てのウォレットを閉じる</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation>%1 のヘルプ メッセージを表示して、使用可能な XPChain のコマンドライン オプションの一覧を見る。</translation> + <translation>%1 のヘルプ メッセージを表示し、使用可能な Bitcoin のコマンドラインオプション一覧を見る。</translation> </message> <message> <source>default wallet</source> @@ -528,7 +544,7 @@ </message> <message> <source>&Window</source> - <translation>ウインドウ (&W)</translation> + <translation>ウィンドウ (&W)</translation> </message> <message> <source>Minimize</source> @@ -627,10 +643,10 @@ <translation>ウォレットは<b>暗号化済み</b>・<b>ロック状態</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>致命的なエラーが発生しました。Bitcoin を安全に動作し続けることができないため終了します。</translation> + <source>Original message:</source> + <translation>オリジナルメッセージ:</translation> </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -731,7 +747,7 @@ </message> <message> <source>Copy fee</source> - <translation>手数料をコピーす</translation> + <translation>手数料をコピー</translation> </message> <message> <source>Copy after fee</source> @@ -767,11 +783,11 @@ </message> <message> <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation>ひとつの入力につき %1 satoshi 前後ずれることがあります。</translation> + <translation>インプット毎に %1 satoshi 前後変動する場合があります。</translation> </message> <message> <source>(no label)</source> - <translation>(ラベル無し)</translation> + <translation>(ラベル無し)</translation> </message> <message> <source>change from %1 (%2)</source> @@ -779,7 +795,7 @@ </message> <message> <source>(change)</source> - <translation>(おつり)</translation> + <translation>(おつり)</translation> </message> </context> <context> @@ -895,7 +911,7 @@ <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation>新しいデータ ディレクトリが作成されます。</translation> + <translation>新しいデータディレクトリが作成されます。</translation> </message> <message> <source>name</source> @@ -926,7 +942,7 @@ </message> <message> <source>Command-line options</source> - <translation>コマンドライン オプション</translation> + <translation>コマンドラインオプション</translation> </message> </context> <context> @@ -945,7 +961,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>OKをクリックすると、%1 は %4 がリリースされた%3年最初の取引からの完全な %4 ブロックチェーン(%2GB)のダウンロードおよび処理を開始します。</translation> + <translation>OKをクリックすると、%1 は %4 がリリースされた%3年における最初の取引からの完全な %4 ブロックチェーン(%2GB)のダウンロードおよび処理を開始します。</translation> </message> <message> <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> @@ -961,11 +977,11 @@ </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> @@ -973,7 +989,7 @@ </message> <message> <source>Discard blocks after verification, except most recent %1 GB (prune)</source> - <translation>最新の%1 GBを除いて、検証後にブロックを破棄 (剪定する)</translation> + <translation>最新の%1 GBを除き、検証後にブロックを破棄する(剪定する)</translation> </message> <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> @@ -1024,7 +1040,7 @@ </message> <message> <source>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> - <translation>まだ表示されていない取引が関係する Bitcoin を使用しようとすると、ネットワークから認証を受けられません。</translation> + <translation>まだ表示されていない取引が関係する Bitcoin の使用を試みた場合、ネットワークから認証を受けられません。</translation> </message> <message> <source>Number of blocks left</source> @@ -1044,7 +1060,7 @@ </message> <message> <source>Progress increase per hour</source> - <translation>一時間あたりの進捗増加</translation> + <translation>一時間毎の進捗増加</translation> </message> <message> <source>calculating...</source> @@ -1052,15 +1068,19 @@ </message> <message> <source>Estimated time left until synced</source> - <translation>同期完了までの推定残り時間</translation> + <translation>同期完了までの推定時間</translation> </message> <message> <source>Hide</source> <translation>隠す</translation> </message> <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> - <translation>%1は現在同期中です。ブロック チェーンの先端に到達するまで、ピアからヘッダーとブロックをダウンロードし検証します。</translation> + <translation>%1は現在同期中です。ブロックチェーンの先端に到達するまで、ピアからヘッダーとブロックをダウンロードし検証します。</translation> </message> <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> @@ -1132,10 +1152,6 @@ <translation>指定されたデフォルト SOCKS5 プロキシが、このネットワークタイプ経由でピアに接続しているかどうか。</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Tor秘匿サービス経由でピアに接続するために専用の SOCKS5 プロキシを利用する(&5):</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>システムトレイのアイコンを隠す</translation> </message> @@ -1213,7 +1229,7 @@ </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> @@ -1268,10 +1284,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Tor秘匿サービスを利用するため、専用の SOCKS5 プロキシ経由で Bitcoin ネットワークに接続する。</translation> - </message> - <message> <source>&Window</source> <translation>ウインドウ(&W)</translation> </message> @@ -1446,7 +1458,46 @@ <source>Current total balance in watch-only addresses</source> <translation>ウォッチ限定アドレスの現在の残高の総計</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>ダイアログ</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>クリップボードにコピー</translation> + </message> + <message> + <source>Save...</source> + <translation>保存</translation> + </message> + <message> + <source>Close</source> + <translation>閉じる</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>トランザクションへの署名が成功しました。トランザクションのブロードキャストの準備ができています。</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>トランザクションデータの保存</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBTはディスクに保存されました。</translation> + </message> + <message> + <source>Total Amount</source> + <translation>合計</translation> + </message> + <message> + <source>or</source> + <translation>または</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1710,10 +1761,6 @@ <translation>ブロック チェーン</translation> </message> <message> - <source>Current number of blocks</source> - <translation>現在のブロック数</translation> - </message> - <message> <source>Memory Pool</source> <translation>メモリ プール</translation> </message> @@ -1758,10 +1805,6 @@ <translation>詳しい情報を見たいピアを選択してください。</translation> </message> <message> - <source>Whitelisted</source> - <translation>ホワイトリスト登録済み</translation> - </message> - <message> <source>Direction</source> <translation>方向</translation> </message> @@ -1782,10 +1825,22 @@ <translation>同期済みブロック</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>ピア選択の多様化に使用できるマップ化された自律システム。</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>マップ化された自律システム</translation> + </message> + <message> <source>User Agent</source> <translation>ユーザーエージェント</translation> </message> <message> + <source>Node window</source> + <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> @@ -1802,10 +1857,6 @@ <translation>サービス</translation> </message> <message> - <source>Ban Score</source> - <translation>Banスコア</translation> - </message> - <message> <source>Connection Time</source> <translation>接続時間</translation> </message> @@ -1954,14 +2005,6 @@ <translation>外向き</translation> </message> <message> - <source>Yes</source> - <translation>はい</translation> - </message> - <message> - <source>No</source> - <translation>いいえ</translation> - </message> - <message> <source>Unknown</source> <translation>不明</translation> </message> @@ -2060,12 +2103,32 @@ <source>Copy amount</source> <translation>金額をコピー</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>ウォレットをアンロックできませんでした。</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QRコード</translation> + <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> <message> <source>Copy &URI</source> @@ -2087,30 +2150,6 @@ <source>Payment information</source> <translation>支払い情報</translation> </message> - <message> - <source>URI</source> - <translation>URI</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> </context> <context> <name>RecentRequestsTableModel</name> @@ -2258,6 +2297,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>ダスト:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>トランザクション手数料の設定を隠す</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>ブロック内の空きよりトランザクション流量が少ない場合、マイナーや中継ノードは最低限の手数料でも処理することがあります。この最低限の手数料だけを支払っても問題ありませんが、一度トランザクションの需要がネットワークの処理能力を超えてしまった場合には、トランザクションが永久に承認されなくなってしまう可能性があることにご注意ください。</translation> </message> @@ -2326,6 +2369,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%1 (%2 ブロック)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>未署名で作成</translation> + </message> + <message> <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> <translation>オフライン%1ウォレットまたはPSBTに対応したハードウェアウォレットと合わせて使用するためのPSBT(部分的に署名されたトランザクション)を作成します。</translation> </message> @@ -2342,10 +2389,18 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%1 送金先: %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>このトランザクションのひな形を作成しますか?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>送金してもよろしいですか?</translation> </message> <message> + <source>Save Transaction Data</source> + <translation>トランザクションデータの保存</translation> + </message> + <message> <source>or</source> <translation>または</translation> </message> @@ -2378,12 +2433,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>送金の確認</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>PSBTをクリップボードにコピー</translation> + <source>Confirm transaction proposal</source> + <translation>トランザクション提案を承認する</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBTがコピーされました</translation> + <source>Send</source> + <translation>送金</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>監視限定残高</translation> </message> <message> <source>The recipient address is not valid. Please recheck.</source> @@ -2481,6 +2540,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>この項目を削除</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>送金する金額の単位を選択</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>手数料は送金する金額から差し引かれます。送金先には金額欄で指定した額よりも少ない Bitcoin が送られます。送金先が複数ある場合は、手数料は均等に分けられます。</translation> </message> @@ -3159,12 +3222,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>ブロックファイル剪定が有効の場合、長期間ウォレットを起動しないと全チェーンを再度同期させる必要があるかもしれません。</translation> </message> + <message> + <source>Close all wallets</source> + <translation>全てのウォレットを閉じる</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>本当に全てのウォレットを閉じますか。</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>ウォレットが読み込まれていません。</translation> + <source>Create a new wallet</source> + <translation>新しいウォレットを作成</translation> </message> </context> <context> @@ -3186,6 +3257,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>手数料を上乗せしてもよろしいですか?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>このトランザクションに手数料を上乗せしたひな形を作成しますか?</translation> + </message> + <message> <source>Current fee:</source> <translation>現在の手数料:</translation> </message> @@ -3202,6 +3277,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>手数料上乗せの確認</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>トランザクションのひな型を作成できませんでした。</translation> + </message> + <message> <source>PSBT copied</source> <translation>PSBTがコピーされました</translation> </message> @@ -3229,6 +3308,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>現在のタブのデータをファイルにエクスポート</translation> </message> <message> + <source>Error</source> + <translation>エラー</translation> + </message> + <message> <source>Backup Wallet</source> <translation>ウォレットのバックアップ</translation> </message> @@ -3272,10 +3355,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>剪定: 最後のウォレット同期ポイントが、剪定されたデータを越えています。-reindex を実行する必要があります (剪定されたノードの場合、ブロックチェーン全体を再ダウンロードします)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>エラー: 致命的な内部エラーが発生しました。詳細は debug.log を参照してください</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>ブロック保存容量を剪定中...</translation> </message> @@ -3288,10 +3367,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%s の開発者</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>おつりアドレスの鍵を作成することができません。内部のキープールに鍵が存在しないため、鍵を生成することができません。</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>データ ディレクトリ %s のロックを取得することができません。%s がおそらく既に実行中です。</translation> </message> @@ -3340,14 +3415,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>警告: ピアと完全に合意が取れていないようです! このノードもしくは他のノードのアップグレードが必要な可能性があります。</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>直近の100ブロックの内、%d ブロックが予期しないバージョンを含んでいます</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s が壊れています。復旧にも失敗しました</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempoolは最低でも %d MB必要です</translation> </message> @@ -3472,10 +3539,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>P2Pアドレスの読み込み中...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>エラー: ディスク容量が不足しています!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>banリストの読み込み中...</translation> </message> @@ -3552,6 +3615,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>非剪定モードに戻るためには -reindex オプションを指定してデータベースを再構築する必要があります。 ブロックチェーン全体の再ダウンロードが必要となります。</translation> </message> <message> + <source>Disk space is too low!</source> + <translation>ディスク容量不足!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>データベースの読み込みエラー。シャットダウンします。</translation> </message> @@ -3658,10 +3725,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>警告: 未知の新しいルールが有効化されました (バージョンビット %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>ウォレットから全取引を消去中...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee が非常に高く設定されています! ひとつの取引でこの金額の手数料が支払われてしまうことがあります。</translation> </message> @@ -3674,10 +3737,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>ネットワークバージョン文字列の長さ(%i)が、最大の長さ(%i) を超えています。UAコメントの数や長さを削減してください。</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>警告: ウォレットファイルが破損していたため、データを復旧しました! 復旧前の %s は %s として %s に保存されました。残高や取引が正しくない場合にはバックアップから復元してください。</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s の設定値が高すぎです!</translation> </message> @@ -3722,10 +3781,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>残高不足</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>分割済みキープールをサポートするようにアップグレードしないと、非HD分割ウォレットをアップグレードすることはできません。 -upgradewallet=169900 オプションか、バージョン指定無しで -upgradewallet オプションを指定してください。</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>手数料推定に失敗しました。代替手数料が無効です。数ブロック待つか、-fallbackfee オプションを有効にしてください。</translation> </message> diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts index 5d230d28c4..3581ba3c59 100644 --- a/src/qt/locale/bitcoin_ka.ts +++ b/src/qt/locale/bitcoin_ka.ts @@ -481,11 +481,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>საფულე <b>დაშიფრულია</b> და ამჟამად <b>დაბლოკილია</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>ფატალური შეცდომა. Bitcoin ვერ უზრუნველყოფს უსაფრთხო გაგრძელებას, ამიტომ იხურება.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -967,6 +963,13 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>ან</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1105,10 +1108,6 @@ <translation>ბლოკთა ჯაჭვი</translation> </message> <message> - <source>Current number of blocks</source> - <translation>ბლოკების მიმდინარე რაოდენობა</translation> - </message> - <message> <source>Last block time</source> <translation>ბოლო ბლოკის დრო</translation> </message> @@ -1215,12 +1214,24 @@ <source>Copy amount</source> <translation>რაოდენობის კოპირება</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>საფულის განბლოკვა ვერ მოხერხდა.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-კოდი</translation> + <source>Amount:</source> + <translation>თანხა:</translation> + </message> + <message> + <source>Message:</source> + <translation>მესიჯი:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>საფულე:</translation> </message> <message> <source>Copy &URI</source> @@ -1242,30 +1253,6 @@ <source>Payment information</source> <translation>ინფორმაცია გადახდის შესახებ</translation> </message> - <message> - <source>URI</source> - <translation>URI</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> </context> <context> <name>RecentRequestsTableModel</name> @@ -2001,11 +1988,7 @@ </context> <context> <name>WalletFrame</name> - <message> - <source>No wallet has been loaded.</source> - <translation>არ არის ჩატვირთული საფულე.</translation> - </message> -</context> + </context> <context> <name>WalletModel</name> <message> @@ -2028,6 +2011,10 @@ <translation>ამ ბარათიდან მონაცემების ექსპორტი ფაილში</translation> </message> <message> + <source>Error</source> + <translation>შეცდომა</translation> + </message> + <message> <source>Backup Wallet</source> <translation>საფულის არქივირება</translation> </message> @@ -2119,10 +2106,6 @@ <translation>ტრანსაქცია ძალიან დიდია</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>ტრანსაქციების ჩახსნა საფულიდან...</translation> - </message> - <message> <source>Unknown network specified in -onlynet: '%s'</source> <translation>-onlynet-ში მითითებულია უცნობი ქსელი: '%s'</translation> </message> diff --git a/src/qt/locale/bitcoin_kk.ts b/src/qt/locale/bitcoin_kk.ts index 9ca9b48149..5b56827b9a 100644 --- a/src/qt/locale/bitcoin_kk.ts +++ b/src/qt/locale/bitcoin_kk.ts @@ -199,6 +199,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -235,14 +238,10 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Amount</source> + <source>Amount:</source> <translation>Саны</translation> </message> - <message> - <source>Wallet</source> - <translation>Әмиян</translation> - </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -335,6 +334,10 @@ <source>&Export</source> <translation>Экспорт</translation> </message> + <message> + <source>Error</source> + <translation>қате</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_km.ts b/src/qt/locale/bitcoin_km.ts index e00ea3145d..20ce9814f8 100644 --- a/src/qt/locale/bitcoin_km.ts +++ b/src/qt/locale/bitcoin_km.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> @@ -11,79 +11,98 @@ </message> <message> <source>&New</source> - <translation>&ថ្មី</translation> + <translation>ថ្មី</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>ចម្លងអាសយដ្ឋានដែលបានរើស</translation> + <translation>ចម្លងអាសយដ្ឋានបច្ចុប្បន្នដែលបានជ្រើសទៅក្ដារតម្រៀបរបស់ប្រព័ន្ធ</translation> </message> <message> <source>&Copy</source> - <translation>&ចម្លង</translation> + <translation>ចម្លង</translation> </message> <message> <source>C&lose</source> - <translation>&បិទ</translation> + <translation>បិទ</translation> </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> </message> <message> <source>Export the data in the current tab to a file</source> - <translation>នាំចេញទិន្នន័យនៃថេបបច្ចុប្បន្នទៅជាឯកសារ</translation> + <translation>នាំចេញទិន្នន័យនៃផ្ទាំងបច្ចុប្បន្នទៅជាឯកសារ</translation> </message> <message> <source>&Export</source> - <translation>&នាំចេញ</translation> + <translation>នាំចេញ</translation> </message> <message> <source>&Delete</source> - <translation>&លុប</translation> + <translation>លុប</translation> </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>ជ្រើសរើស</translation> </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> </message> <message> <source>&Copy Address</source> - <translation>&ចម្លងអាស្រយដ្ឋាន</translation> + <translation>ចម្លងអាសយដ្ឋាន</translation> </message> <message> <source>Copy &Label</source> - <translation>ចម្លង&ឡាបែល</translation> + <translation>ចម្លង ស្លាក</translation> </message> <message> <source>&Edit</source> - <translation>&កែ</translation> + <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> + <translation>ការនាំចេញបានបរាជ័យ</translation> </message> - </context> + <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> + <translation>ស្លាក</translation> </message> <message> <source>Address</source> @@ -91,65 +110,289 @@ </message> <message> <source>(no label)</source> - <translation>(គ្មានឡាបែល)</translation> + <translation>(គ្មានស្លាក)</translation> </message> </context> <context> <name>AskPassphraseDialog</name> <message> + <source>Passphrase Dialog</source> + <translation>ការហៅឃ្លាសម្ងាត់</translation> + </message> + <message> <source>Enter passphrase</source> - <translation>បញ្ចូលពាក្យសម្ងាត់</translation> + <translation>បញ្ចូលឃ្លាសម្ងាត់</translation> </message> <message> <source>New passphrase</source> - <translation>ពាក្យសម្ងាត់ថ្មី</translation> + <translation>ឃ្លាសម្ងាត់ថ្មី</translation> </message> <message> <source>Repeat new passphrase</source> - <translation>វាយពាក្យសម្ងាត់ម្ដងទៀត</translation> + <translation>ឃ្លាសម្ងាត់ថ្នីម្ដងទៀត</translation> + </message> + <message> + <source>Show passphrase</source> + <translation>បង្ហាញឃ្លាសម្ងាត់</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> </message> <message> <source>Unlock wallet</source> - <translation>ដោះសោរកាបូបលុយ</translation> + <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> + <translation>ឌិគ្រីបកាបូបចល័ត</translation> </message> <message> <source>Change passphrase</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> + <translation>ការព្រមាន៖ ប្រសិនបើអ្នកអ៊ិនគ្រីបកាបូបចល័តរបស់អ្នក ហើយអ្នកភ្លេចបាត់ឃ្លាសម្ងាត់ នោះអ្នកនិង <b>បាត់បង់ BITCOINS របស់អ្នកទាំងអស់</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> + <translation>កាបូបចល័ត ដែលបានអ៊ិនគ្រីប</translation> + </message> + <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>បញ្ចូលឃ្លាសម្ងាត់សំរាប់កាបូប។ សូមប្រើឃ្លាសម្ងាត់ពី១០ តួរឬច្រើនជាងនេះ, ឬ ៨ពាក្យឬច្រើនជាងនេះ</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>វាយបញ្ចូលឃ្លាសម្ងាត់ចាស់ និងឃ្លាសសម្លាត់ថ្មី សម្រាប់កាបូបចល័តរបស់អ្នក។</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>កាបូបចល័ត ដែលត្រូវបានអ៊ិនគ្រីប</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>កាបូបចល័តរបស់អ្នក ជិតត្រូវបានអ៊ិនគ្រីបហើយ។</translation> + </message> + <message> + <source>Your wallet is now encrypted. </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> + <translation>បរាជ័យដោះសោរកាបូបចល័ត</translation> </message> - </context> + <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> + <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>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>Open &URI...</source> + <translation>បើក URL...</translation> + </message> + <message> + <source>Create Wallet...</source> + <translation>បង្កើតកាបូបចល័ត...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>បង្កើតកាបូបចល័តថ្មី</translation> + </message> + <message> + <source>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>Proxy is <b>enabled</b>: %1</source> + <translation>ប្រូកស៊ី ត្រូវបាន <b>អនុញ្ញាត</b>៖ %1</translation> + </message> + <message> <source>Send coins to a Bitcoin address</source> <translation>ផ្ញើកាក់ទៅកាន់ អាសយដ្ឋាន Bitcoin មួយ</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> + <message> + <source>&Verify message...</source> + <translation>ផ្ទៀងផ្ទាត់សារ...</translation> + </message> + <message> + <source>&Send</source> + <translation>ផ្ងើ</translation> + </message> + <message> + <source>&Receive</source> + <translation>ទទួល</translation> + </message> + <message> + <source>&Show / Hide</source> + <translation>បង្ហាញ/លាក់បាំង</translation> + </message> + <message> + <source>Show or hide the main Window</source> + <translation>បង្ហាញ រឺលាក់ផ្ទាំងវីនដូដើម</translation> + </message> + <message> + <source>&File</source> + <translation>ឯកសារ</translation> + </message> + <message> + <source>&Settings</source> + <translation>ការកំណត់</translation> + </message> + <message> + <source>Error</source> + <translation>បញ្ហា</translation> + </message> </context> <context> <name>CoinControlDialog</name> @@ -163,6 +406,14 @@ </context> <context> <name>CreateWalletDialog</name> + <message> + <source>Create Wallet</source> + <translation>បង្កើតកាបូប</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>ឈ្មោះកាបូប</translation> + </message> </context> <context> <name>EditAddressDialog</name> @@ -175,6 +426,18 @@ </context> <context> <name>Intro</name> + <message> + <source>Welcome</source> + <translation>សូមស្វាគមន៍</translation> + </message> + <message> + <source>Bitcoin</source> + <translation>Bitcoin</translation> + </message> + <message> + <source>Error</source> + <translation>បញ្ហា</translation> + </message> </context> <context> <name>ModalOverlay</name> @@ -187,11 +450,18 @@ </context> <context> <name>OptionsDialog</name> + <message> + <source>Error</source> + <translation>បញ្ហា</translation> + </message> </context> <context> <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -212,18 +482,10 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>អាសយដ្ឋាន</translation> - </message> - <message> - <source>Label</source> - <translation>ឡាបែល</translation> - </message> - <message> - <source>Wallet</source> - <translation>កាបូប</translation> + <source>Wallet:</source> + <translation>កាបូបចល័ត៖</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -274,6 +536,10 @@ <context> <name>TransactionView</name> <message> + <source>Comma separated file (*.csv)</source> + <translation>ឯកសារបំបែកដោយក្បៀស (*.csv)</translation> + </message> + <message> <source>Label</source> <translation>ឡាបែល</translation> </message> @@ -294,7 +560,11 @@ </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>បង្កើតកាបូបចល័តថ្មី</translation> + </message> +</context> <context> <name>WalletModel</name> </context> @@ -308,6 +578,10 @@ <source>Export the data in the current tab to a file</source> <translation>នាំចេញទិន្នន័យនៃថេបបច្ចុប្បន្នទៅជាឯកសារ</translation> </message> + <message> + <source>Error</source> + <translation>បញ្ហា</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_ko.ts b/src/qt/locale/bitcoin_ko.ts index 7cc6797c21..00944be3ef 100644 --- a/src/qt/locale/bitcoin_ko.ts +++ b/src/qt/locale/bitcoin_ko.ts @@ -70,10 +70,6 @@ <translation>비트코인을 보내는 계좌 주소입니다. 코인을 보내기 전에 금액과 받는 주소를 항상 확인하세요.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>지불 수신용 비트코인주소. 신규 주소를 만들려면 'Create new receiving address' 버튼을 사용하세요.</translation> - </message> - <message> <source>&Copy Address</source> <translation>주소 복사(&C)</translation> </message> @@ -188,6 +184,22 @@ <translation>지갑의 이전 비밀번호와 새로운 비밀번호를 입력하세요.</translation> </message> <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>지갑을 암호화 해도 컴퓨터에 바이러스가 있을시 안전하기 않다는 것을 참고하세요.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>암호화할 지갑</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>지갑이 바로 암호화 됩니다.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>지갑이 암호화 되었습니다.</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> @@ -310,6 +322,14 @@ <translation>&URI 열기...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>지갑 생성하기...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>새로운 지갑 생성하기</translation> + </message> + <message> <source>Wallet:</source> <translation>지갑:</translation> </message> @@ -458,6 +478,14 @@ <translation>최신의</translation> </message> <message> + <source>Node window</source> + <translation>노드 창</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>노드 디버깅 및 진단 콘솔 열기 </translation> + </message> + <message> <source>&Sending addresses</source> <translation>보내는 주소(&S)</translation> </message> @@ -466,6 +494,10 @@ <translation>받는 주소(&R)</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>bitcoin: URI 열기</translation> + </message> + <message> <source>Open Wallet</source> <translation>지갑 열기</translation> </message> @@ -526,6 +558,10 @@ <translation>오류: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>경고: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>날짜: %1 @@ -589,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>지갑이 <b>암호화</b> 되었고 현재 <b>잠겨져</b> 있습니다</translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>치명적인 오류가 발생했습니다. 비트코인을 더이상 안전하게 진행할 수 없어 곧 종료합니다.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -747,10 +779,50 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>지갑 <b>%1</b> 생성중...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>지갑 생성하기 실패</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>지갑 생성 경고</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>지갑 생성하기</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>지갑 이름</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>지갑 암호화하기. 해당 지갑은 당신이 설정한 문자열 비밀번호로 암호화될 겁니다.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>지갑 암호화</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>개인키 비활성화 하기</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>빈 지갑 만들기</translation> + </message> + <message> + <source>Create</source> + <translation>생성하기</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -914,7 +986,11 @@ <source>(of %n GB needed)</source> <translation><numerusform>(%n GB가 필요)</numerusform></translation> </message> - </context> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(Full 체인이 되려면 %n GB 가 필요합니다)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -962,6 +1038,10 @@ <translation>숨기기</translation> </message> <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>알 수 없음. 헤더 동기화 중(%1,%2%)...</translation> </message> @@ -969,6 +1049,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>비트코인 URI 열기</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -976,6 +1060,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>지갑 열기 실패</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>지갑 열기 경고</translation> + </message> + <message> <source>default wallet</source> <translation>기본 지갑</translation> </message> @@ -1019,10 +1111,6 @@ <translation>제공된 기본 SOCKS5 프록시가 이 네트워크 유형을 통해 피어에 도달하는 경우 표시됩니다.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Tor 서비스를 이용하여 피어에게 연결하기 위해 분리된 SOCKS5 프록시 사용:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>시스템 트레이 로 부터 아이콘 숨기기</translation> </message> @@ -1155,10 +1243,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Tor 서비스를 경유하여 비트코인 네트워크에 연결하기 위해 분리된 SOCKS5 프록시를 사용합니다.</translation> - </message> - <message> <source>&Window</source> <translation>창(&W)</translation> </message> @@ -1333,7 +1417,18 @@ <source>Current total balance in watch-only addresses</source> <translation>조회전용 주소의 현재 잔액</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>총액</translation> + </message> + <message> + <source>or</source> + <translation>또는</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1353,6 +1448,18 @@ <translation>'bitcoin://"은 잘못된 URI입니다. 'bitcoin:'을 사용하십시오.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>BIP70을 지원하지 않아서 지불 요청을 처리할 수 없습니다.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>BIP70의 보안적 결함 때문에 상점에 불문하고 "지갑을 바꾸라"라는 권고 또는 지시는 대부분의 경우 무시하는 방법을 강력하게 권장합니다.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>만약 이 오류 메시지가 보인다면, 상점에 BIP21이 호환되는 URI를 제공해달라고 요청해주세요.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>잘못된 지불 주소 %1</translation> </message> @@ -1514,6 +1621,10 @@ <translation>URI를 QR 코드로 인코딩하는 중 오류가 발생했습니다.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>QR 코드를 지원하지 않습니다.</translation> + </message> + <message> <source>Save QR Code</source> <translation>QR코드 저장</translation> </message> @@ -1581,10 +1692,6 @@ <translation>블록 체인</translation> </message> <message> - <source>Current number of blocks</source> - <translation>현재 블록 수</translation> - </message> - <message> <source>Memory Pool</source> <translation>메모리 풀</translation> </message> @@ -1629,10 +1736,6 @@ <translation>자세한 정보를 보려면 피어를 선택하세요.</translation> </message> <message> - <source>Whitelisted</source> - <translation>화이트리스트에 포함</translation> - </message> - <message> <source>Direction</source> <translation>방향</translation> </message> @@ -1657,6 +1760,10 @@ <translation>유저 에이전트</translation> </message> <message> + <source>Node window</source> + <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> @@ -1673,10 +1780,6 @@ <translation>서비스</translation> </message> <message> - <source>Ban Score</source> - <translation>밴 스코어</translation> - </message> - <message> <source>Connection Time</source> <translation>접속 시간</translation> </message> @@ -1825,14 +1928,6 @@ <translation>아웃바운드</translation> </message> <message> - <source>Yes</source> - <translation>예</translation> - </message> - <message> - <source>No</source> - <translation>아니오</translation> - </message> - <message> <source>Unknown</source> <translation>알수없음</translation> </message> @@ -1868,6 +1963,10 @@ <translation>요청할 금액 입력칸으로 선택 사항입니다. 빈 칸으로 두거나 특정 금액이 필요하지 않는 경우 0을 입력하세요.</translation> </message> <message> + <source>&Create new receiving address</source> + <translation>&새 받을 주소 생성하기</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>양식의 모든 필드를 지웁니다.</translation> </message> @@ -1919,12 +2018,24 @@ <source>Copy amount</source> <translation>거래액 복사</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>지갑을 잠금해제 할 수 없습니다.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR 코드</translation> + <source>Amount:</source> + <translation>거래액:</translation> + </message> + <message> + <source>Message:</source> + <translation>메시지:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>지갑:</translation> </message> <message> <source>Copy &URI</source> @@ -1946,30 +2057,6 @@ <source>Payment information</source> <translation>지불 정보</translation> </message> - <message> - <source>URI</source> - <translation>URI</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> </context> <context> <name>RecentRequestsTableModel</name> @@ -2117,6 +2204,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>더스트:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>거래 수수료 설정 숨기기</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>거래량이 블록에 남은 공간보다 적은 경우에는 채굴자나 중계 노드들이 최소 수수료를 허용할 수 있습니다. 최소 수수료만 지불하는건 괜찮지만, 네트워크가 처리할 수 있는 용량을 넘는 비트코인 거래가 있을 경우에는 이 거래가 승인이 안될 수 있다는 점을 유의하세요.</translation> </message> @@ -2185,6 +2276,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%1(%2 블록)</translation> </message> <message> + <source> from wallet '%1'</source> + <translation>%1 지갑에서</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1을(를) %2(으)로</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1을(를) %2(으)로</translation> </message> @@ -2217,10 +2316,22 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>총액</translation> </message> <message> + <source>To review recipient list click "Show Details..."</source> + <translation>수령인 목록을 검토하려면 "거래 세부 내역 보기" 를 클릭하십시오</translation> + </message> + <message> <source>Confirm send coins</source> <translation>코인 전송을 확인</translation> </message> <message> + <source>Send</source> + <translation>보내기</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>조회전용 잔액:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>수령인 주소가 정확하지 않습니다. 재확인 바랍니다</translation> </message> @@ -2474,6 +2585,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>지갑 잠금 해제를 취소했습니다.</translation> </message> <message> + <source>No error</source> + <translation>오류 없음</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>입력한 주소에 대한 개인키가 없습니다.</translation> </message> @@ -2648,6 +2763,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>출력 인덱스</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(인증서가 확인되지 않았습니다)</translation> + </message> + <message> <source>Merchant</source> <translation>상점</translation> </message> @@ -2971,15 +3090,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>지갑 닫기</translation> </message> <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>정말로 지갑 <i>%1</i> 을 닫겠습니까?</translation> + </message> + <message> <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>블록축소를 하고 지갑을 너무 오랫동안 닫으면 체인 전체를 다시 동기화해야 할 수도 있습니다.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>지갑 불러오기가 안됩니다.</translation> + <source>Create a new wallet</source> + <translation>새로운 지갑 생성하기</translation> </message> </context> <context> @@ -3017,6 +3140,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>수수료 상향 승인</translation> </message> <message> + <source>PSBT copied</source> + <translation>PSBT 복사됨</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>거래에 서명 할 수 없습니다.</translation> </message> @@ -3040,6 +3167,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>현재 탭에 있는 데이터를 파일로 내보내기</translation> </message> <message> + <source>Error</source> + <translation>오류</translation> + </message> + <message> <source>Backup Wallet</source> <translation>지갑 백업</translation> </message> @@ -3083,10 +3214,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>블록 축소: 마지막 지갑 동기화 지점이 축소된 데이터보다 과거의 것 입니다. -reindex가 필요합니다 (축소된 노드의 경우 모든 블록체인을 재다운로드합니다)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>오류: 치명적인 내부 오류가 발생했습니다, 자세한 내용은 debug.log 를 확인해주세요.</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>블록 데이터를 축소 중입니다..</translation> </message> @@ -3099,10 +3226,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%s 개발자</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>거스름돈 주소 생성 불가. 내장 지갑 열쇠 보관함에 열쇠가 없으면 새로운 열쇠를 생성할 수 없습니다.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>%s 데이터 디렉토리에 락을 걸 수 없었습니다. %s가 이미 실행 중인 것으로 보입니다.</translation> </message> @@ -3151,14 +3274,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>경고: 현재 비트코인 버전이 다른 네트워크 참여자들과 동일하지 않은 것 같습니다. 당신 또는 다른 참여자들이 동일한 비트코인 버전으로 업그레이드 할 필요가 있습니다.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>지난 100개의 블록 중 %d개에 예상치 못한 버전이 있습니다.</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s 손상되었고 복구가 실패하였습니다</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool은 최소한 %d MB 이어야 합니다</translation> </message> @@ -3183,6 +3298,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>손상된 블록 데이터베이스가 감지되었습니다</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>asmap file %s 을/를 찾을 수 없습니다</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>asmap file %s 을/를 파싱할 수 없습니다</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>블록 데이터베이스를 다시 생성하시겠습니까?</translation> </message> @@ -3239,6 +3362,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>무결성 확인 초기화가 실패했습니다. %s가 종료됩니다.</translation> </message> <message> + <source>Invalid P2P permission: '%s'</source> + <translation>잘못된 P2P 권한: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation>유효하지 않은 금액 -%s=<amount>: '%s'</translation> </message> @@ -3255,6 +3382,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>지정한 블록 디렉토리 "%s" 가 존재하지 않습니다.</translation> </message> <message> + <source>Unknown change type '%s'</source> + <translation>알 수 없는 변경 형식 '%s'</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>txindex 데이터베이스 업테이트중</translation> </message> @@ -3371,6 +3502,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>-whitebind: '%s' 를 이용하여 포트를 지정해야 합니다</translation> </message> <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>블록 축소 모드는 -blockfileterindex와 호환되지 않습니다.</translation> + </message> + <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> <translation>시스템 한계로 인하여 -maxconnections를 %d 에서 %d로 줄였습니다.</translation> </message> @@ -3429,6 +3564,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>초기 키값 생성 불가</translation> </message> <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>알 수 없는 -blockfileterindex 값 %s.</translation> + </message> + <message> <source>Verifying wallet(s)...</source> <translation>지갑 검증중...</translation> </message> @@ -3437,10 +3576,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>경고: 알려지지 않은 새로운 규칙이 활성화되었습니다. (버전비트 %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>지갑의 모든거래내역 건너뛰기...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee 값이 너무 큽니다! 하나의 거래에 너무 큰 수수료가 지불 됩니다.</translation> </message> @@ -3453,10 +3588,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>네트워크 버전 문자 (%i)의 길이가 최대길이 (%i)를 초과합니다. uacomments의 갯수나 길이를 줄이세요.</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>경고 : 지갑파일이 손상되어 데이터가 복구되었습니다. 원래의 %s 파일은 %s 후에 %s 이름으로 저장됩니다. 잔액과 거래 내역이 정확하지 않다면 백업 파일로 부터 복원해야 합니다.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s가 매우 높게 설정되었습니다!</translation> </message> @@ -3501,10 +3632,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>잔액이 부족합니다</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>HD split을 하지 않은 지갑은 pre split keypool로 업그레이드 하지 않은 이상 업그레이드가 불가능합니다. -upgradewallet=169900 이나 -upgradewallet (버전을 정하지 않고) 명령을 사용하십시오.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>수수료 추정이 실패했습니다. Fallbackfee가 비활성화 상태입니다. 몇 블록을 기다리거나 -fallbackfee를 활성화 하세요.</translation> </message> diff --git a/src/qt/locale/bitcoin_ku_IQ.ts b/src/qt/locale/bitcoin_ku_IQ.ts index 68ddf09ddc..8552770aea 100644 --- a/src/qt/locale/bitcoin_ku_IQ.ts +++ b/src/qt/locale/bitcoin_ku_IQ.ts @@ -171,6 +171,13 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>یان</translation> + </message> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -256,14 +263,6 @@ <source>never</source> <translation>هەرگیز</translation> </message> - <message> - <source>Yes</source> - <translation>بەڵێ</translation> - </message> - <message> - <source>No</source> - <translation>نەخێر</translation> - </message> </context> <context> <name>ReceiveCoinsDialog</name> @@ -291,16 +290,12 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>ناوونیشان</translation> - </message> - <message> - <source>Amount</source> - <translation>سەرجەم</translation> + <source>Amount:</source> + <translation>کۆ:</translation> </message> <message> - <source>Message</source> - <translation>پەیام</translation> + <source>Message:</source> + <translation>پەیام:</translation> </message> </context> <context> @@ -447,6 +442,10 @@ <source>&Export</source> <translation>&هەناردن</translation> </message> + <message> + <source>Error</source> + <translation>هەڵە</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_ky.ts b/src/qt/locale/bitcoin_ky.ts index bfb9c663fd..04fabae0e4 100644 --- a/src/qt/locale/bitcoin_ky.ts +++ b/src/qt/locale/bitcoin_ky.ts @@ -163,6 +163,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -215,18 +218,10 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>Дарек</translation> - </message> - <message> - <source>Message</source> - <translation>Билдирүү</translation> - </message> - <message> - <source>Wallet</source> - <translation>Капчык</translation> + <source>Message:</source> + <translation>Билдирүү:</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -335,6 +330,10 @@ </context> <context> <name>WalletView</name> + <message> + <source>Error</source> + <translation>Ката</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts index 830a665844..2eaf377d65 100644 --- a/src/qt/locale/bitcoin_la.ts +++ b/src/qt/locale/bitcoin_la.ts @@ -341,11 +341,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Cassidile <b>cifratum</b> est et iam nunc <b>seratum</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Error fatalis accidit. Bitcoin nondum pergere tute potest, et exibit.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -595,6 +591,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> <message> <source>Cannot start bitcoin: click-to-pay handler</source> @@ -669,10 +668,6 @@ <translation>Catena frustorum</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Numerus frustorum iam nunc</translation> - </message> - <message> <source>Last block time</source> <translation>Hora postremi frusti</translation> </message> @@ -715,34 +710,30 @@ <source>Copy amount</source> <translation>Copia quantitatem</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>&Copia Inscriptionem</translation> - </message> - <message> - <source>Address</source> - <translation>Inscriptio</translation> + <source>Could not unlock wallet.</source> + <translation>Non potuisse cassidile reserare</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Amount</source> - <translation>Quantitas</translation> + <source>Amount:</source> + <translation>Quantitas:</translation> </message> <message> - <source>Label</source> - <translation>Titulus</translation> + <source>Label:</source> + <translation>Titulus:</translation> </message> <message> - <source>Message</source> - <translation>Nuntius</translation> + <source>Message:</source> + <translation>Nuntius:</translation> </message> <message> - <source>Wallet</source> - <translation>Cassidile</translation> + <source>Copy &Address</source> + <translation>&Copia Inscriptionem</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1320,6 +1311,10 @@ <translation>Exporta data in hac tabella in plicam</translation> </message> <message> + <source>Error</source> + <translation>Error</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Conserva cassidile</translation> </message> diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts index afdc7ffb8d..1c1fc292bf 100644 --- a/src/qt/locale/bitcoin_lt.ts +++ b/src/qt/locale/bitcoin_lt.ts @@ -176,6 +176,10 @@ <translation>Piniginė užšifruota</translation> </message> <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Įveskite seną ir naują slaptažodį.</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> @@ -298,6 +302,14 @@ <translation>Atidaryti &URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Sukurti piniginę...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Sukurti naują piniginę</translation> + </message> + <message> <source>Wallet:</source> <translation>Piniginė</translation> </message> @@ -478,6 +490,10 @@ <translation>numatyta piniginė</translation> </message> <message> + <source>No wallets available</source> + <translation>Piniginių nėra</translation> + </message> + <message> <source>&Window</source> <translation>&Langas</translation> </message> @@ -510,6 +526,10 @@ <translation>Klaida: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>Įspėjimas: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>Data: %1 @@ -573,11 +593,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Piniginė <b>užšifruota</b> ir šiuo metu <b>užrakinta</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Kritinė klaida. Bitcoin nebegali tęsti saugiai ir bus išjungtas.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -731,10 +747,50 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Sukuriama Piniginė <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Piniginės sukurimas nepavyko</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Piniginės sukurimo įspėjimas</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Sukurti Piniginę</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Piniginės Pavadinimas</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Užkoduoti piniginę. Piniginė bus užkoduota jūsų pasirinkta slapta fraze.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Užkoduoti Piniginę</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Atjungti Privačius Raktus</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Sukurti Tuščia Piniginę</translation> + </message> + <message> + <source>Create</source> + <translation>Sukurti</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -867,6 +923,10 @@ <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Ištrinti blokus po patikrinimo, išskyrus paskutinius %1 GB (nukarpimas)</translation> + </message> + <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <translation>Šiame kataloge bus saugomi bent %1 GB duomenų, kurie laikui bėgant didės.</translation> </message> @@ -960,6 +1020,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Piniginės atidarymas nepavyko</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Piniginės atidarymo įspėjimas</translation> + </message> + <message> <source>default wallet</source> <translation>numatyta piniginė</translation> </message> @@ -1003,10 +1071,6 @@ <translation>Rodo, ar pridedamas numatytasis SOCKS5 proxy naudojamas pasiekti Peers per šį tinklo tipą.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Naudokite atskirą SOCKS&5 tarpinius serverius, kad pasiektumėte Peers per „Tor“ paslėptas paslaugas:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Slėpti piktogramą</translation> </message> @@ -1139,10 +1203,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Prisijunkite prie „Bitcoin“ tinklo per atskirą „SOCKS5“ proxy „Tor“ paslėptas paslaugas.</translation> - </message> - <message> <source>&Window</source> <translation>&Langas</translation> </message> @@ -1317,7 +1377,22 @@ <source>Current total balance in watch-only addresses</source> <translation>Dabartinis visas balansas tik stebimų adresų</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialogas</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Visas kiekis</translation> + </message> + <message> + <source>or</source> + <translation>ar</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1498,6 +1573,10 @@ <translation>Klaida koduojant URI į QR kodą.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>QR kodas nepalaikomas</translation> + </message> + <message> <source>Save QR Code</source> <translation>Įrašyti QR kodą</translation> </message> @@ -1565,10 +1644,6 @@ <translation>Blokų grandinė</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Dabartinis blokų skaičius</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memory Pool</translation> </message> @@ -1613,10 +1688,6 @@ <translation>Pasirinkite peer, kad galėtumėte peržiūrėti išsamią informaciją.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Baltasis sąrašas</translation> - </message> - <message> <source>Direction</source> <translation>Kryptis</translation> </message> @@ -1657,10 +1728,6 @@ <translation>Paslaugos</translation> </message> <message> - <source>Ban Score</source> - <translation>Uždraudimo balas</translation> - </message> - <message> <source>Connection Time</source> <translation>Ryšio laikas</translation> </message> @@ -1809,14 +1876,6 @@ <translation>Išsiunčiamas</translation> </message> <message> - <source>Yes</source> - <translation>Taip</translation> - </message> - <message> - <source>No</source> - <translation>Ne</translation> - </message> - <message> <source>Unknown</source> <translation>Nežinomas</translation> </message> @@ -1903,12 +1962,28 @@ <source>Copy amount</source> <translation>Kopijuoti sumą</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Nepavyko atrakinti piniginės.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR kodas</translation> + <source>Amount:</source> + <translation>Suma:</translation> + </message> + <message> + <source>Label:</source> + <translation>Žymė:</translation> + </message> + <message> + <source>Message:</source> + <translation>Žinutė:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Piniginė</translation> </message> <message> <source>Copy &URI</source> @@ -1930,30 +2005,6 @@ <source>Payment information</source> <translation>Mokėjimo informacija</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adresas</translation> - </message> - <message> - <source>Amount</source> - <translation>Suma</translation> - </message> - <message> - <source>Label</source> - <translation>Žymė</translation> - </message> - <message> - <source>Message</source> - <translation>Žinutė</translation> - </message> - <message> - <source>Wallet</source> - <translation>Piniginė</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2169,6 +2220,14 @@ Pastaba: Kadangi mokestis apskaičiuojamas pagal baitą, mokestis už „100 sat <translation>%1 (%2 blokai)</translation> </message> <message> + <source> from wallet '%1'</source> + <translation>iš piniginės '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>'%1' į '%2'</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 iki %2</translation> </message> @@ -2918,12 +2977,16 @@ Pastaba: Kadangi mokestis apskaičiuojamas pagal baitą, mokestis už „100 sat <source>Close wallet</source> <translation>Uždaryti Piniginę</translation> </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Ar tikrai norite uždaryti piniginę <i>%1</i>?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Piniginė nebuvo įkelta.</translation> + <source>Create a new wallet</source> + <translation>Sukurti naują piniginę</translation> </message> </context> <context> @@ -2984,6 +3047,10 @@ Pastaba: Kadangi mokestis apskaičiuojamas pagal baitą, mokestis už „100 sat <translation>Eksportuokite duomenis iš dabartinio skirtuko į failą</translation> </message> <message> + <source>Error</source> + <translation>Klaida</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Sukurti Piniginės atsarginę kopiją</translation> </message> @@ -3019,14 +3086,6 @@ Pastaba: Kadangi mokestis apskaičiuojamas pagal baitą, mokestis už „100 sat <translation>%s kūrėjai</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d iš paskutinių 100 blokų turi nenumatyą versiją</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s sugadintas, išgelbėjimas nepavyko</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool turi būti bent %d MB</translation> </message> @@ -3091,6 +3150,10 @@ Pastaba: Kadangi mokestis apskaičiuojamas pagal baitą, mokestis už „100 sat <translation>Importuojama...</translation> </message> <message> + <source>Unknown address type '%s'</source> + <translation>Nežinomas adreso tipas '%s'</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Txindex duomenų bazės atnaujinimas</translation> </message> @@ -3151,10 +3214,6 @@ Pastaba: Kadangi mokestis apskaičiuojamas pagal baitą, mokestis už „100 sat <translation>Tikrinama piniginė(s)...</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Visų operacijų sulaikymas iš piniginės...</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s labai aukštas!</translation> </message> diff --git a/src/qt/locale/bitcoin_lv.ts b/src/qt/locale/bitcoin_lv.ts index a5c96c1a2a..5ac13296e8 100644 --- a/src/qt/locale/bitcoin_lv.ts +++ b/src/qt/locale/bitcoin_lv.ts @@ -50,6 +50,18 @@ <translation>Izvēlies adresi ar kuru saņemt bitcoins</translation> </message> <message> + <source>C&hoose</source> + <translation>Izvēlēties</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Adrešu nosūtīšana</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Adrešu saņemšana</translation> + </message> + <message> <source>&Copy Address</source> <translation>&Kopēt adresi</translation> </message> @@ -104,6 +116,10 @@ <translation>Jaunā parole vēlreiz</translation> </message> <message> + <source>Show passphrase</source> + <translation>Rādīt paroli</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Šifrēt maciņu</translation> </message> @@ -116,6 +132,10 @@ <translation>Atšifrēt maciņu</translation> </message> <message> + <source>Change passphrase</source> + <translation>Mainīt paroli</translation> + </message> + <message> <source>Confirm wallet encryption</source> <translation>Apstiprināt maciņa šifrēšanu</translation> </message> @@ -124,6 +144,14 @@ <translation>Vai tu tiešām vēlies šifrēt savu maciņu?</translation> </message> <message> + <source>Wallet encrypted</source> + <translation>Maciņš šifrēts</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Maciņš tagad šifrēts</translation> + </message> + <message> <source>Wallet encryption failed</source> <translation>Maciņa šifrēšana neizdevās</translation> </message> @@ -194,6 +222,10 @@ <translation>Atvērt &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Maciņš:</translation> + </message> + <message> <source>Reindexing blocks on disk...</source> <translation>Bloku reindeksēšana no diska...</translation> </message> @@ -647,6 +679,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -741,10 +776,6 @@ <translation>Bloku virkne</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Pašreizējais bloku skaits</translation> - </message> - <message> <source>Last block time</source> <translation>Pēdējā bloka laiks</translation> </message> @@ -827,8 +858,16 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Kods</translation> + <source>Amount:</source> + <translation>Daudzums:</translation> + </message> + <message> + <source>Message:</source> + <translation>Ziņojums:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Maciņš:</translation> </message> <message> <source>Copy &URI</source> @@ -842,23 +881,7 @@ <source>&Save Image...</source> <translation>&Saglabāt Attēlu...</translation> </message> - <message> - <source>Address</source> - <translation>Adrese</translation> - </message> - <message> - <source>Amount</source> - <translation>Daudzums</translation> - </message> - <message> - <source>Label</source> - <translation>Nosaukums</translation> - </message> - <message> - <source>Wallet</source> - <translation>Maciņš</translation> - </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1183,6 +1206,10 @@ <source>Export the data in the current tab to a file</source> <translation>Datus no tekošā ieliktņa eksportēt uz failu</translation> </message> + <message> + <source>Error</source> + <translation>Kļūda</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_mk.ts b/src/qt/locale/bitcoin_mk.ts index 72aea8582f..1c430b486b 100644 --- a/src/qt/locale/bitcoin_mk.ts +++ b/src/qt/locale/bitcoin_mk.ts @@ -349,6 +349,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -465,8 +468,12 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Код</translation> + <source>Amount:</source> + <translation>Сума:</translation> + </message> + <message> + <source>Message:</source> + <translation>Порака:</translation> </message> <message> <source>Copy &URI</source> @@ -480,15 +487,7 @@ <source>&Save Image...</source> <translation>&Сними Слика...</translation> </message> - <message> - <source>Amount</source> - <translation>Сума</translation> - </message> - <message> - <source>Wallet</source> - <translation>Паричник</translation> - </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -597,6 +596,10 @@ <source>Export the data in the current tab to a file</source> <translation>Експортирај ги податоците од активното јазиче во датотека</translation> </message> + <message> + <source>Error</source> + <translation>Грешка</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_ml.ts b/src/qt/locale/bitcoin_ml.ts index 299d81bf75..86e9a55d33 100644 --- a/src/qt/locale/bitcoin_ml.ts +++ b/src/qt/locale/bitcoin_ml.ts @@ -129,6 +129,10 @@ <translation>പുതിയ രഹസ്യപദപ്രയോഗം ആവർത്തിക്കുക</translation> </message> <message> + <source>Show passphrase</source> + <translation>രഹസ്യപദം കാണിക്കുക </translation> + </message> + <message> <source>Encrypt wallet</source> <translation>വാലറ്റ് എൻക്രിപ്റ്റ് ചെയ്യുക</translation> </message> @@ -160,16 +164,174 @@ <source>Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>!</source> <translation>മുന്നറിയിപ്പ്: നിങ്ങളുടെ വാലറ്റ് എൻക്രിപ്റ്റ് ചെയ്ത് പാസ്ഫ്രെയ്സ് നഷ്ടപ്പെടുകയാണെങ്കിൽ, നിങ്ങളുടെ എല്ലാ ബിറ്റ്കൊയിനുകളും നഷ്ടപ്പെടും!</translation> </message> + <message> + <source>Wallet encrypted</source> + <translation>വാലറ്റ് എന്ക്രിപ്റ് ചെയ്തു കഴിഞ്ഞു .</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>വാലെറ്റിന്റെ പഴയ രഹസ്യപദവും പുതിയ രഹസ്യപദവും നൽകുക.</translation> + </message> </context> <context> <name>BanTableModel</name> </context> <context> <name>BitcoinGUI</name> + <message> + <source>Browse transaction history</source> + <translation>ഇടപാടുകളുടെ ചരിത്രം പരിശോധിയ്ക്കുക</translation> + </message> + <message> + <source>Error</source> + <translation>പിശക് </translation> + </message> + <message> + <source>Warning</source> + <translation>മുന്നറിയിപ്പ് </translation> + </message> + <message> + <source>Information</source> + <translation>വിവരം </translation> + </message> + <message> + <source>Open Wallet</source> + <translation>വാലറ്റ് തുറക്കുക </translation> + </message> + <message> + <source>Open a wallet</source> + <translation>ഒരു വാലറ്റ് തുറക്കുക </translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>വാലറ്റ് പൂട്ടുക </translation> + </message> + <message> + <source>Close wallet</source> + <translation>വാലറ്റ് പൂട്ടുക </translation> + </message> + <message> + <source>default wallet</source> + <translation>സ്ഥിരം ആയ വാലറ്റ്</translation> + </message> + <message> + <source>No wallets available</source> + <translation>വാലറ്റ് ഒന്നും ലഭ്യം അല്ല </translation> + </message> + <message> + <source>Minimize</source> + <translation>ചെറുതാക്കുക </translation> + </message> + <message> + <source>Zoom</source> + <translation>വലുതാക്കുക </translation> + </message> + <message> + <source>Main Window</source> + <translation>മുഖ്യ ജാലകം </translation> + </message> + <message> + <source>Connecting to peers...</source> + <translation>സുഹൃത്തുക്കളും ആയി കണക്ട് ചെയ്യുന്നു ...</translation> + </message> + <message> + <source>Error: %1</source> + <translation>തെറ്റ് : %1 </translation> + </message> + <message> + <source>Warning: %1</source> + <translation>മുന്നറിയിപ്പ് : %1 </translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>തീയതി: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>തുക : %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>വാലറ്റ്: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>കുറിപ്പ് : %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>മേൽവിലാസം : %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation>അയച്ച ഇടപാടുകൾ </translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>വരവ്വ് വെച്ച ഇടപാടുകൾ </translation> + </message> </context> <context> <name>CoinControlDialog</name> <message> + <source>Coin Selection</source> + <translation>കോയിൻ തിരഞ്ഞെടുക്കൽ </translation> + </message> + <message> + <source>Quantity:</source> + <translation>നിര്ദ്ധിഷ്ടസംഖ്യ / അളവ് :</translation> + </message> + <message> + <source>Bytes:</source> + <translation>ബൈറ്റ്സ്:</translation> + </message> + <message> + <source>Amount:</source> + <translation>തുക:</translation> + </message> + <message> + <source>Fee:</source> + <translation>ഫീസ് / പ്രതിഫലം :</translation> + </message> + <message> + <source>List mode</source> + <translation>പട്ടിക </translation> + </message> + <message> + <source>Amount</source> + <translation>തുക </translation> + </message> + <message> + <source>Received with label</source> + <translation>അടയാളത്തോടുകൂടി ലഭിച്ചു </translation> + </message> + <message> + <source>Received with address</source> + <translation>മേൽവിലാസത്തോടുകൂടി ലഭിച്ചു </translation> + </message> + <message> + <source>Date</source> + <translation>തീയതി </translation> + </message> + <message> + <source>Confirmations</source> + <translation>സ്ഥിതീകരണങ്ങൾ </translation> + </message> + <message> + <source>Confirmed</source> + <translation>സ്ഥിതീകരിച്ചു</translation> + </message> + <message> <source>(no label)</source> <translation>(ലേബൽ ഇല്ല)</translation> </message> @@ -179,33 +341,80 @@ </context> <context> <name>CreateWalletDialog</name> + <message> + <source>Create Wallet</source> + <translation>വാലറ്റ് / പണസഞ്ചി സൃഷ്ടിക്കുക :</translation> + </message> </context> <context> <name>EditAddressDialog</name> </context> <context> <name>FreespaceChecker</name> + <message> + <source>name</source> + <translation>നാമധേയം / പേര് </translation> + </message> </context> <context> <name>HelpMessageDialog</name> </context> <context> <name>Intro</name> + <message> + <source>Error</source> + <translation>പിശക് </translation> + </message> </context> <context> <name>ModalOverlay</name> + <message> + <source>Unknown...</source> + <translation>അജ്ഞാതമായ </translation> + </message> + <message> + <source>Progress</source> + <translation>പുരോഗതി</translation> + </message> + <message> + <source>calculating...</source> + <translation>കണക്കായ്ക്കിക്കൊണ്ടിരിക്കുന്നു</translation> + </message> </context> <context> <name>OpenURIDialog</name> </context> <context> <name>OpenWalletActivity</name> + <message> + <source>default wallet</source> + <translation>സ്ഥിരം ആയ വാലറ്റ്</translation> + </message> </context> <context> <name>OptionsDialog</name> + <message> + <source>Error</source> + <translation>പിശക് </translation> + </message> </context> <context> <name>OverviewPage</name> + <message> + <source>Available:</source> + <translation>ലഭ്യമായ</translation> + </message> + <message> + <source>Spendable:</source> + <translation>വിനിയോഗിക്കാവുന്നത് / ചെലവാക്കാവുന്നത് </translation> + </message> + <message> + <source>Recent transactions</source> + <translation>സമീപ കാല ഇടപാടുകൾ</translation> + </message> + </context> +<context> + <name>PSBTOperationsDialog</name> </context> <context> <name>PaymentServer</name> @@ -215,6 +424,14 @@ </context> <context> <name>QObject</name> + <message> + <source>Amount</source> + <translation>തുക </translation> + </message> + <message> + <source>Error: %1</source> + <translation>തെറ്റ് : %1 </translation> + </message> </context> <context> <name>QRImageWidget</name> @@ -228,17 +445,17 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>വിലാസം</translation> - </message> - <message> - <source>Label</source> - <translation>ലേബൽ</translation> + <source>Amount:</source> + <translation>തുക:</translation> </message> </context> <context> <name>RecentRequestsTableModel</name> <message> + <source>Date</source> + <translation>തീയതി </translation> + </message> + <message> <source>Label</source> <translation>ലേബൽ</translation> </message> @@ -250,6 +467,26 @@ <context> <name>SendCoinsDialog</name> <message> + <source>Quantity:</source> + <translation>നിര്ദ്ധിഷ്ടസംഖ്യ / അളവ് :</translation> + </message> + <message> + <source>Bytes:</source> + <translation>ബൈറ്റ്സ്:</translation> + </message> + <message> + <source>Amount:</source> + <translation>തുക:</translation> + </message> + <message> + <source>Fee:</source> + <translation>ഫീസ് / പ്രതിഫലം :</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>പെയ്മെന്റിനുള്ള അഭ്യർത്ഥന കാലഹരണപ്പെട്ടു പോയിരിക്കുന്നു. </translation> + </message> + <message> <source>(no label)</source> <translation>(ലേബൽ ഇല്ല)</translation> </message> @@ -268,6 +505,14 @@ </context> <context> <name>TransactionDesc</name> + <message> + <source>Date</source> + <translation>തീയതി </translation> + </message> + <message> + <source>Amount</source> + <translation>തുക </translation> + </message> </context> <context> <name>TransactionDescDialog</name> @@ -275,6 +520,10 @@ <context> <name>TransactionTableModel</name> <message> + <source>Date</source> + <translation>തീയതി </translation> + </message> + <message> <source>Label</source> <translation>ലേബൽ</translation> </message> @@ -290,6 +539,14 @@ <translation>കോമയാൽ വേർതിരിച്ച ഫയൽ (* .csv)</translation> </message> <message> + <source>Confirmed</source> + <translation>സ്ഥിതീകരിച്ചു</translation> + </message> + <message> + <source>Date</source> + <translation>തീയതി </translation> + </message> + <message> <source>Label</source> <translation>ലേബൽ</translation> </message> @@ -307,13 +564,21 @@ </context> <context> <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>വാലറ്റ് പൂട്ടുക </translation> + </message> </context> <context> <name>WalletFrame</name> </context> <context> <name>WalletModel</name> - </context> + <message> + <source>default wallet</source> + <translation>സ്ഥിരം ആയ വാലറ്റ്</translation> + </message> +</context> <context> <name>WalletView</name> <message> @@ -324,6 +589,10 @@ <source>Export the data in the current tab to a file</source> <translation>നിലവിലെ ടാബിൽ ഒരു ഫയലിൽ ഡാറ്റ എക്സ്പോർട്ട് ചെയ്യുക</translation> </message> + <message> + <source>Error</source> + <translation>പിശക് </translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_mn.ts b/src/qt/locale/bitcoin_mn.ts index 0423c35a68..dabfb97f3b 100644 --- a/src/qt/locale/bitcoin_mn.ts +++ b/src/qt/locale/bitcoin_mn.ts @@ -439,6 +439,13 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>эсвэл</translation> + </message> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -501,10 +508,6 @@ <translation>Блокийн цуваа</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Одоогийн блокийн тоо</translation> - </message> - <message> <source>Last block time</source> <translation>Сүүлийн блокийн хугацаа</translation> </message> @@ -559,34 +562,26 @@ <source>Copy amount</source> <translation>Хэмжээг санах</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> - <message> - <source>Copy &Address</source> - <translation>Хаягийг &Хуулбарлах</translation> - </message> - <message> - <source>Address</source> - <translation>Хаяг</translation> - </message> <message> - <source>Amount</source> - <translation>Хэмжээ</translation> + <source>Could not unlock wallet.</source> + <translation>Түрүйвчийн цоожийг тайлж чадсангүй</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Label</source> - <translation>Шошго</translation> + <source>Amount:</source> + <translation>Хэмжээ:</translation> </message> <message> - <source>Message</source> - <translation>Зурвас</translation> + <source>Message:</source> + <translation>Зурвас:</translation> </message> <message> - <source>Wallet</source> - <translation>Түрүйвч</translation> + <source>Copy &Address</source> + <translation>Хаягийг &Хуулбарлах</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -993,11 +988,7 @@ </context> <context> <name>WalletFrame</name> - <message> - <source>No wallet has been loaded.</source> - <translation>Ямар ч түрүйвч ачааллагдсангүй.</translation> - </message> -</context> + </context> <context> <name>WalletModel</name> <message> @@ -1015,6 +1006,10 @@ <source>Export the data in the current tab to a file</source> <translation>Сонгогдсон таб дээрхи дата-г экспортлох</translation> </message> + <message> + <source>Error</source> + <translation>Алдаа</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_mr_IN.ts b/src/qt/locale/bitcoin_mr_IN.ts index 4a74385b29..22eef2605c 100644 --- a/src/qt/locale/bitcoin_mr_IN.ts +++ b/src/qt/locale/bitcoin_mr_IN.ts @@ -30,6 +30,10 @@ <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> @@ -77,10 +81,30 @@ <source>&Edit</source> <translation>&संपादित</translation> </message> + <message> + <source>Export Address List</source> + <translation>पत्त्याची निर्यात करा</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> </context> @@ -92,6 +116,10 @@ </context> <context> <name>CoinControlDialog</name> + <message> + <source>(no label)</source> + <translation>(लेबल नाही)</translation> + </message> </context> <context> <name>CreateWalletActivity</name> @@ -127,6 +155,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -149,10 +180,22 @@ </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> - </context> + <message> + <source>(no label)</source> + <translation>(लेबल नाही)</translation> + </message> +</context> <context> <name>SendCoinsEntry</name> </context> @@ -173,9 +216,29 @@ </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>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_ms.ts b/src/qt/locale/bitcoin_ms.ts index f5f5bb7a87..4d51ebba02 100644 --- a/src/qt/locale/bitcoin_ms.ts +++ b/src/qt/locale/bitcoin_ms.ts @@ -134,6 +134,10 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Ulangi frasa laluan baru</translation> </message> <message> + <source>Show passphrase</source> + <translation>Show passphrase</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Dompet encrypt</translation> </message> @@ -174,6 +178,30 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Dompet dienkripsi</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Enter the old passphrase and new passphrase for the wallet.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Wallet to be encrypted</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Your wallet is about to be encrypted. </translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Your wallet is now encrypted. </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: Apa-apa sandaran yang anda buat sebelum ini untuk fail dompet anda hendaklah digantikan dengan fail dompet enkripsi yang dijana baru. Untuk sebab-sebab keselamatan , sandaran fail dompet yang belum dibuat enkripsi sebelum ini akan menjadi tidak berguna secepat anda mula guna dompet enkripsi baru.</translation> </message> @@ -296,6 +324,14 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Buka &URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Create Wallet...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Create a new wallet</translation> + </message> + <message> <source>Wallet:</source> <translation>dompet</translation> </message> @@ -320,6 +356,10 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Reindexi blok pada cakera...</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>Menghantar koin kepada alamat Bitcoin</translation> </message> @@ -391,6 +431,34 @@ Alihkan fail data ke dalam tab semasa</translation> </translation> </message> <message> + <source>Show the list of used receiving addresses and labels</source> + <translation>Show the list of used receiving addresses and labels</translation> + </message> + <message> + <source>&Command-line options</source> + <translation>&Command-line options</translation> + </message> + <message> + <source>Indexing blocks on disk...</source> + <translation>Indexing blocks on disk...</translation> + </message> + <message> + <source>Processing blocks on disk...</source> + <translation>Processing blocks on disk...</translation> + </message> + <message> + <source>%1 behind</source> + <translation>%1 behind</translation> + </message> + <message> + <source>Last received block was generated %1 ago.</source> + <translation>Last received block was generated %1 ago.</translation> + </message> + <message> + <source>Transactions after this will not yet be visible.</source> + <translation>Transactions after this will not yet be visible.</translation> + </message> + <message> <source>Error</source> <translation>Ralat</translation> </message> @@ -407,10 +475,34 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Terkini</translation> </message> <message> + <source>Node window</source> + <translation>Node window</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Open node debugging and diagnostic console</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation>&Sending addresses</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Receiving addresses</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation>Open a bitcoin: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Buka Wallet</translation> </message> <message> + <source>Open a wallet</source> + <translation>Open a wallet</translation> + </message> + <message> <source>Close Wallet...</source> <translation>Tutup Wallet...</translation> </message> @@ -419,28 +511,324 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Tutup Wallet</translation> </message> <message> + <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> + <translation>Show the %1 help message to get a list with possible Bitcoin command-line options</translation> + </message> + <message> <source>default wallet</source> <translation>dompet lalai </translation> </message> + <message> + <source>No wallets available</source> + <translation>No wallets available</translation> + </message> + <message> + <source>&Window</source> + <translation>&Window</translation> + </message> + <message> + <source>Minimize</source> + <translation>Minimize</translation> + </message> + <message> + <source>Zoom</source> + <translation>Zoom</translation> + </message> + <message> + <source>Main Window</source> + <translation>Main Window</translation> + </message> + <message> + <source>%1 client</source> + <translation>%1 client</translation> + </message> + <message> + <source>Connecting to peers...</source> + <translation>Connecting to peers...</translation> + </message> + <message> + <source>Catching up...</source> + <translation>Catching up...</translation> + </message> + <message> + <source>Error: %1</source> + <translation>Error: %1</translation> + </message> + <message> + <source>Warning: %1</source> + <translation>Warning: %1</translation> + </message> + <message> + <source>Date: %1 +</source> + <translation>Date: %1 +</translation> + </message> + <message> + <source>Amount: %1 +</source> + <translation>Amount: %1 +</translation> + </message> + <message> + <source>Wallet: %1 +</source> + <translation>Wallet: %1 +</translation> + </message> + <message> + <source>Type: %1 +</source> + <translation>Type: %1 +</translation> + </message> + <message> + <source>Label: %1 +</source> + <translation>Label: %1 +</translation> + </message> + <message> + <source>Address: %1 +</source> + <translation>Address: %1 +</translation> + </message> + <message> + <source>Sent transaction</source> + <translation>Sent transaction</translation> + </message> + <message> + <source>Incoming transaction</source> + <translation>Incoming transaction</translation> + </message> + <message> + <source>HD key generation is <b>enabled</b></source> + <translation>HD key generation is <b>enabled</b></translation> + </message> + <message> + <source>HD key generation is <b>disabled</b></source> + <translation>HD key generation is <b>disabled</b></translation> + </message> + <message> + <source>Private key <b>disabled</b></source> + <translation>Private key <b>disabled</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> + <translation>Wallet is <b>encrypted</b> and currently <b>unlocked</b></translation> + </message> + <message> + <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> + <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> + </message> </context> <context> <name>CoinControlDialog</name> <message> + <source>Coin Selection</source> + <translation>Coin Selection</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Quantity:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Amount:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Fee:</translation> + </message> + <message> + <source>Dust:</source> + <translation>Dust:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>After Fee:</translation> + </message> + <message> + <source>Change:</source> + <translation>Change:</translation> + </message> + <message> + <source>(un)select all</source> + <translation>(un)select all</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Tree mode</translation> + </message> + <message> + <source>List mode</source> + <translation>List mode</translation> + </message> + <message> <source>Amount</source> <translation>Amount</translation> </message> <message> + <source>Received with label</source> + <translation>Received with label</translation> + </message> + <message> + <source>Received with address</source> + <translation>Received with address</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Confirmations</source> + <translation>Confirmations</translation> + </message> + <message> + <source>Confirmed</source> + <translation>Confirmed</translation> + </message> + <message> + <source>Copy address</source> + <translation>Copy address</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Copy transaction ID</translation> + </message> + <message> + <source>Lock unspent</source> + <translation>Lock unspent</translation> + </message> + <message> + <source>Unlock unspent</source> + <translation>Unlock unspent</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Copy quantity</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Copy fee</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Copy after fee</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Copy bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Copy dust</translation> + </message> + <message> + <source>Copy change</source> + <translation>Copy change</translation> + </message> + <message> + <source>(%1 locked)</source> + <translation>(%1 locked)</translation> + </message> + <message> + <source>yes</source> + <translation>yes</translation> + </message> + <message> + <source>no</source> + <translation>no</translation> + </message> + <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>This label turns red if any recipient receives an amount smaller than the current dust threshold.</translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Can vary +/- %1 satoshi(s) per input.</translation> + </message> + <message> <source>(no label)</source> <translation>(tiada label)</translation> </message> - </context> + <message> + <source>change from %1 (%2)</source> + <translation>change from %1 (%2)</translation> + </message> + <message> + <source>(change)</source> + <translation>(change)</translation> + </message> +</context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Creating Wallet <b>%1</b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Create wallet failed</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Create wallet warning</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Create Wallet</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Wallet Name</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Encrypt Wallet</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Disable Private Keys</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Make Blank Wallet</translation> + </message> + <message> + <source>Create</source> + <translation>Create</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -448,36 +836,244 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Alamat</translation> </message> <message> + <source>&Label</source> + <translation>&Label</translation> + </message> + <message> + <source>The label associated with this address list entry</source> + <translation>The label associated with this address list entry</translation> + </message> + <message> + <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> + <translation>The address associated with this address list entry. This can only be modified for sending addresses.</translation> + </message> + <message> <source>&Address</source> <translation>Alamat</translation> </message> - </context> + <message> + <source>New sending address</source> + <translation>New sending address</translation> + </message> + <message> + <source>Edit receiving address</source> + <translation>Edit receiving address</translation> + </message> + <message> + <source>Edit sending address</source> + <translation>Edit sending address</translation> + </message> + <message> + <source>The entered address "%1" is not a valid Bitcoin address.</source> + <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> + <message> + <source>New key generation failed.</source> + <translation>New key generation failed.</translation> + </message> +</context> <context> <name>FreespaceChecker</name> - </context> + <message> + <source>A new data directory will be created.</source> + <translation>A new data directory will be created.</translation> + </message> + <message> + <source>name</source> + <translation>name</translation> + </message> + <message> + <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> + <translation>Directory already exists. Add %1 if you intend to create a new directory here.</translation> + </message> + <message> + <source>Path already exists, and is not a directory.</source> + <translation>Path already exists, and is not a directory.</translation> + </message> + <message> + <source>Cannot create data directory here.</source> + <translation>Cannot create data directory here.</translation> + </message> +</context> <context> <name>HelpMessageDialog</name> - </context> + <message> + <source>version</source> + <translation>version</translation> + </message> + <message> + <source>About %1</source> + <translation>About %1</translation> + </message> + <message> + <source>Command-line options</source> + <translation>Command-line options</translation> + </message> +</context> <context> <name>Intro</name> <message> + <source>Welcome</source> + <translation>Welcome</translation> + </message> + <message> + <source>Welcome to %1.</source> + <translation>Welcome to %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>As this is the first time the program is launched, you can choose where %1 will store its data.</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>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.</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</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>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.</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>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> + </message> + <message> + <source>Use the default data directory</source> + <translation>Use the default data directory</translation> + </message> + <message> + <source>Use a custom data directory:</source> + <translation>Use a custom data directory:</translation> + </message> + <message> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Discard blocks after verification, except most recent %1 GB (prune)</translation> + </message> + <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>At least %1 GB of data will be stored in this directory, and it will grow over time.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Approximately %1 GB of data will be stored in this directory.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 will download and store a copy of the Bitcoin block chain.</translation> + </message> + <message> + <source>The wallet will also be stored in this directory.</source> + <translation>The wallet will also be stored in this directory.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>Error: Specified data directory "%1" cannot be created.</translation> + </message> + <message> <source>Error</source> <translation>Ralat</translation> </message> </context> <context> <name>ModalOverlay</name> - </context> + <message> + <source>Form</source> + <translation>Form</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>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.</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>Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</translation> + </message> + <message> + <source>Number of blocks left</source> + <translation>Number of blocks left</translation> + </message> + <message> + <source>Unknown...</source> + <translation>Unknown...</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>Progress</source> + <translation>Progress</translation> + </message> + <message> + <source>Progress increase per hour</source> + <translation>Progress increase per hour</translation> + </message> + <message> + <source>calculating...</source> + <translation>calculating...</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation>Estimated time left until synced</translation> + </message> + <message> + <source>Hide</source> + <translation>Hide</translation> + </message> + <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Unknown. Syncing Headers (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> - </context> + <message> + <source>Open bitcoin URI</source> + <translation>Open bitcoin URI</translation> + </message> + <message> + <source>URI:</source> + <translation>URI:</translation> + </message> +</context> <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Open wallet failed</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Open wallet warning</translation> + </message> + <message> <source>default wallet</source> <translation>dompet lalai </translation> @@ -490,120 +1086,1971 @@ Alihkan fail data ke dalam tab semasa</translation> <context> <name>OptionsDialog</name> <message> + <source>Options</source> + <translation>Options</translation> + </message> + <message> + <source>&Main</source> + <translation>&Main</translation> + </message> + <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Automatically start %1 after logging in to the system.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Start %1 on system login</translation> + </message> + <message> + <source>Size of &database cache</source> + <translation>Size of &database cache</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation>Number of script &verification threads</translation> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>IP address of the proxy (e.g. 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>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</translation> + </message> + <message> + <source>Hide the icon from the system tray.</source> + <translation>Hide the icon from the system tray.</translation> + </message> + <message> + <source>&Hide tray icon</source> + <translation>&Hide tray icon</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>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.</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>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 |.</translation> + </message> + <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Open the %1 configuration file from the working directory.</translation> + </message> + <message> + <source>Open Configuration File</source> + <translation>Open Configuration File</translation> + </message> + <message> + <source>Reset all client options to default.</source> + <translation>Reset all client options to default.</translation> + </message> + <message> + <source>&Reset Options</source> + <translation>&Reset Options</translation> + </message> + <message> + <source>&Network</source> + <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>MiB</source> + <translation>MiB</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = auto, <0 = leave that many cores free)</translation> + </message> + <message> + <source>W&allet</source> + <translation>W&allet</translation> + </message> + <message> + <source>Expert</source> + <translation>Expert</translation> + </message> + <message> + <source>Enable coin &control features</source> + <translation>Enable coin &control features</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>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.</translation> + </message> + <message> + <source>&Spend unconfirmed change</source> + <translation>&Spend unconfirmed change</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>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <translation>Map port using &UPnP</translation> + </message> + <message> + <source>Accept connections from outside.</source> + <translation>Accept connections from outside.</translation> + </message> + <message> + <source>Allow incomin&g connections</source> + <translation>Allow incomin&g connections</translation> + </message> + <message> + <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> + <translation>Connect to the Bitcoin network through a SOCKS5 proxy.</translation> + </message> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Connect through SOCKS5 proxy (default 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 of the proxy (e.g. 9050)</translation> + </message> + <message> + <source>Used for reaching peers via:</source> + <translation>Used for reaching peers via:</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>&Window</translation> + </message> + <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation>Show only a tray icon after minimizing the window.</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation>&Minimize to the tray instead of the taskbar</translation> + </message> + <message> + <source>M&inimize on close</source> + <translation>M&inimize on close</translation> + </message> + <message> + <source>&Display</source> + <translation>&Display</translation> + </message> + <message> + <source>User Interface &language:</source> + <translation>User Interface &language:</translation> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>The user interface language can be set here. This setting will take effect after restarting %1.</translation> + </message> + <message> + <source>&Unit to show amounts in:</source> + <translation>&Unit to show amounts in:</translation> + </message> + <message> + <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> + <translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation> + </message> + <message> + <source>Whether to show coin control features or not.</source> + <translation>Whether to show coin control features or not.</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>&Third party transaction URLs</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Options set in this dialog are overridden by the command line or in the configuration file:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancel</translation> + </message> + <message> + <source>default</source> + <translation>default</translation> + </message> + <message> + <source>none</source> + <translation>none</translation> + </message> + <message> + <source>Confirm options reset</source> + <translation>Confirm options reset</translation> + </message> + <message> + <source>Client restart required to activate changes.</source> + <translation>Client restart required to activate changes.</translation> + </message> + <message> + <source>Client will be shut down. Do you want to proceed?</source> + <translation>Client will be shut down. Do you want to proceed?</translation> + </message> + <message> + <source>Configuration options</source> + <translation>Configuration options</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>The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</translation> + </message> + <message> <source>Error</source> <translation>Ralat</translation> </message> - </context> + <message> + <source>The configuration file could not be opened.</source> + <translation>The configuration file could not be opened.</translation> + </message> + <message> + <source>This change would require a client restart.</source> + <translation>This change would require a client restart.</translation> + </message> + <message> + <source>The supplied proxy address is invalid.</source> + <translation>The supplied proxy address is invalid.</translation> + </message> +</context> <context> <name>OverviewPage</name> + <message> + <source>Form</source> + <translation>Form</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>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.</translation> + </message> + <message> + <source>Watch-only:</source> + <translation>Watch-only:</translation> + </message> + <message> + <source>Available:</source> + <translation>Available:</translation> + </message> + <message> + <source>Your current spendable balance</source> + <translation>Your current spendable balance</translation> + </message> + <message> + <source>Pending:</source> + <translation>Pending:</translation> + </message> + <message> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> + </message> + <message> + <source>Immature:</source> + <translation>Immature:</translation> + </message> + <message> + <source>Mined balance that has not yet matured</source> + <translation>Mined balance that has not yet matured</translation> + </message> + <message> + <source>Balances</source> + <translation>Balances</translation> + </message> + <message> + <source>Total:</source> + <translation>Total:</translation> + </message> + <message> + <source>Your current total balance</source> + <translation>Your current total balance</translation> + </message> + <message> + <source>Your current balance in watch-only addresses</source> + <translation>Your current balance in watch-only addresses</translation> + </message> + <message> + <source>Spendable:</source> + <translation>Spendable:</translation> + </message> + <message> + <source>Recent transactions</source> + <translation>Recent transactions</translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Unconfirmed transactions to watch-only addresses</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Mined balance in watch-only addresses that has not yet matured</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Current total balance in watch-only addresses</translation> + </message> </context> <context> - <name>PaymentServer</name> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> + </message> </context> <context> + <name>PaymentServer</name> + <message> + <source>Payment request error</source> + <translation>Payment request error</translation> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Cannot start bitcoin: click-to-pay handler</translation> + </message> + <message> + <source>URI handling</source> + <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>Cannot process payment request because BIP70 is not supported.</source> + <translation>Cannot process payment request because BIP70 is not supported.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</translation> + </message> + <message> + <source>Invalid payment address %1</source> + <translation>Invalid payment address %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 cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Payment request file handling</translation> + </message> +</context> +<context> <name>PeerTableModel</name> - </context> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node/Service</source> + <translation>Node/Service</translation> + </message> + <message> + <source>NodeId</source> + <translation>NodeId</translation> + </message> + <message> + <source>Ping</source> + <translation>Ping</translation> + </message> + <message> + <source>Sent</source> + <translation>Sent</translation> + </message> + <message> + <source>Received</source> + <translation>Received</translation> + </message> +</context> <context> <name>QObject</name> <message> <source>Amount</source> <translation>Amount</translation> </message> - </context> + <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Enter a Bitcoin address (e.g. %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>None</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 and %2</source> + <translation>%1 and %2</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>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> + <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 didn't yet exit safely...</translation> + </message> + <message> + <source>unknown</source> + <translation>unknown</translation> + </message> +</context> <context> <name>QRImageWidget</name> - </context> + <message> + <source>&Save Image...</source> + <translation>&Save Image...</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&Copy Image</translation> + </message> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation>Resulting URI too long, try to reduce the text for label / message.</translation> + </message> + <message> + <source>Error encoding URI into QR Code.</source> + <translation>Error encoding URI into QR Code.</translation> + </message> + <message> + <source>QR code support not available.</source> + <translation>QR code support not available.</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>Save QR Code</translation> + </message> + <message> + <source>PNG Image (*.png)</source> + <translation>PNG Image (*.png)</translation> + </message> +</context> <context> <name>RPCConsole</name> - </context> + <message> + <source>N/A</source> + <translation>N/A</translation> + </message> + <message> + <source>Client version</source> + <translation>Client version</translation> + </message> + <message> + <source>&Information</source> + <translation>&Information</translation> + </message> + <message> + <source>General</source> + <translation>General</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Using BerkeleyDB version</translation> + </message> + <message> + <source>Datadir</source> + <translation>Datadir</translation> + </message> + <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>To specify a non-default location of the data directory use the '%1' option.</translation> + </message> + <message> + <source>Blocksdir</source> + <translation>Blocksdir</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>To specify a non-default location of the blocks directory use the '%1' option.</translation> + </message> + <message> + <source>Startup time</source> + <translation>Startup time</translation> + </message> + <message> + <source>Network</source> + <translation>Network</translation> + </message> + <message> + <source>Name</source> + <translation>Name</translation> + </message> + <message> + <source>Number of connections</source> + <translation>Number of connections</translation> + </message> + <message> + <source>Block chain</source> + <translation>Block chain</translation> + </message> + <message> + <source>Memory Pool</source> + <translation>Memory Pool</translation> + </message> + <message> + <source>Current number of transactions</source> + <translation>Current number of transactions</translation> + </message> + <message> + <source>Memory usage</source> + <translation>Memory usage</translation> + </message> + <message> + <source>Wallet: </source> + <translation>Wallet: </translation> + </message> + <message> + <source>(none)</source> + <translation>(none)</translation> + </message> + <message> + <source>&Reset</source> + <translation>&Reset</translation> + </message> + <message> + <source>Received</source> + <translation>Received</translation> + </message> + <message> + <source>Sent</source> + <translation>Sent</translation> + </message> + <message> + <source>&Peers</source> + <translation>&Peers</translation> + </message> + <message> + <source>Banned peers</source> + <translation>Banned peers</translation> + </message> + <message> + <source>Select a peer to view detailed information.</source> + <translation>Select a peer to view detailed information.</translation> + </message> + <message> + <source>Direction</source> + <translation>Direction</translation> + </message> + <message> + <source>Version</source> + <translation>Version</translation> + </message> + <message> + <source>Starting Block</source> + <translation>Starting Block</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Synced Headers</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Synced Blocks</translation> + </message> + <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>The mapped Autonomous System used for diversifying peer selection.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapped AS</translation> + </message> + <message> + <source>User Agent</source> + <translation>User Agent</translation> + </message> + <message> + <source>Node window</source> + <translation>Node window</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>Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</translation> + </message> + <message> + <source>Decrease font size</source> + <translation>Decrease font size</translation> + </message> + <message> + <source>Increase font size</source> + <translation>Increase font size</translation> + </message> + <message> + <source>Services</source> + <translation>Services</translation> + </message> + <message> + <source>Connection Time</source> + <translation>Connection Time</translation> + </message> + <message> + <source>Last Send</source> + <translation>Last Send</translation> + </message> + <message> + <source>Last Receive</source> + <translation>Last Receive</translation> + </message> + <message> + <source>Ping Time</source> + <translation>Ping Time</translation> + </message> + <message> + <source>The duration of a currently outstanding ping.</source> + <translation>The duration of a currently outstanding ping.</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>Ping Wait</translation> + </message> + <message> + <source>Min Ping</source> + <translation>Min Ping</translation> + </message> + <message> + <source>Time Offset</source> + <translation>Time Offset</translation> + </message> + <message> + <source>Last block time</source> + <translation>Last block time</translation> + </message> + <message> + <source>&Open</source> + <translation>&Open</translation> + </message> + <message> + <source>&Console</source> + <translation>&Console</translation> + </message> + <message> + <source>&Network Traffic</source> + <translation>&Network Traffic</translation> + </message> + <message> + <source>Totals</source> + <translation>Totals</translation> + </message> + <message> + <source>In:</source> + <translation>In:</translation> + </message> + <message> + <source>Out:</source> + <translation>Out:</translation> + </message> + <message> + <source>Debug log file</source> + <translation>Debug log file</translation> + </message> + <message> + <source>Clear console</source> + <translation>Clear console</translation> + </message> + <message> + <source>1 &hour</source> + <translation>1 &hour</translation> + </message> + <message> + <source>1 &day</source> + <translation>1 &day</translation> + </message> + <message> + <source>1 &week</source> + <translation>1 &week</translation> + </message> + <message> + <source>1 &year</source> + <translation>1 &year</translation> + </message> + <message> + <source>&Disconnect</source> + <translation>&Disconnect</translation> + </message> + <message> + <source>Ban for</source> + <translation>Ban for</translation> + </message> + <message> + <source>&Unban</source> + <translation>&Unban</translation> + </message> + <message> + <source>Welcome to the %1 RPC console.</source> + <translation>Welcome to the %1 RPC console.</translation> + </message> + <message> + <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> + <translation>Use up and down arrows to navigate history, and %1 to clear screen.</translation> + </message> + <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Type %1 for an overview of available commands.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>For more information on using this console type %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>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.</translation> + </message> + <message> + <source>Network activity disabled</source> + <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> + <message> + <source>via %1</source> + <translation>via %1</translation> + </message> + <message> + <source>never</source> + <translation>never</translation> + </message> + <message> + <source>Inbound</source> + <translation>Inbound</translation> + </message> + <message> + <source>Outbound</source> + <translation>Outbound</translation> + </message> + <message> + <source>Unknown</source> + <translation>Unknown</translation> + </message> +</context> <context> <name>ReceiveCoinsDialog</name> + <message> + <source>&Amount:</source> + <translation>&Amount:</translation> + </message> + <message> + <source>&Label:</source> + <translation>&Label:</translation> + </message> + <message> + <source>&Message:</source> + <translation>&Message:</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>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.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <translation>An optional label to associate with the new receiving address.</translation> + </message> + <message> + <source>Use this form to request payments. All fields are <b>optional</b>.</source> + <translation>Use this form to request payments. All fields are <b>optional</b>.</translation> + </message> + <message> + <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <translation>An optional amount to request. Leave this empty or zero to not request a specific amount.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>An optional message that is attached to the payment request and may be displayed to the sender.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Create new receiving address</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Clear all fields of the form.</translation> + </message> + <message> + <source>Clear</source> + <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> + <message> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation>Show the selected request (does the same as double clicking an entry)</translation> + </message> + <message> + <source>Show</source> + <translation>Show</translation> + </message> + <message> + <source>Remove the selected entries from the list</source> + <translation>Remove the selected entries from the list</translation> + </message> + <message> + <source>Remove</source> + <translation>Remove</translation> + </message> + <message> + <source>Copy URI</source> + <translation>Copy URI</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy message</source> + <translation>Copy message</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Could not unlock wallet.</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>&Salin Alamat</translation> + <source>Amount:</source> + <translation>Amount:</translation> </message> <message> - <source>Address</source> - <translation>Alamat</translation> + <source>Message:</source> + <translation>Message:</translation> </message> <message> - <source>Amount</source> - <translation>Amount</translation> + <source>Wallet:</source> + <translation>dompet</translation> </message> <message> - <source>Label</source> - <translation>Label</translation> + <source>Copy &URI</source> + <translation>Copy &URI</translation> </message> <message> - <source>Wallet</source> - <translation>dompet</translation> + <source>Copy &Address</source> + <translation>&Salin Alamat</translation> + </message> + <message> + <source>&Save Image...</source> + <translation>&Save Image...</translation> + </message> + <message> + <source>Request payment to %1</source> + <translation>Request payment to %1</translation> + </message> + <message> + <source>Payment information</source> + <translation>Payment information</translation> </message> </context> <context> <name>RecentRequestsTableModel</name> <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> <source>Label</source> <translation>Label</translation> </message> <message> + <source>Message</source> + <translation>Message</translation> + </message> + <message> <source>(no label)</source> <translation>(tiada label)</translation> </message> - </context> + <message> + <source>(no message)</source> + <translation>(no message)</translation> + </message> + <message> + <source>(no amount requested)</source> + <translation>(no amount requested)</translation> + </message> + <message> + <source>Requested</source> + <translation>Requested</translation> + </message> +</context> <context> <name>SendCoinsDialog</name> <message> + <source>Send Coins</source> + <translation>Send Coins</translation> + </message> + <message> + <source>Coin Control Features</source> + <translation>Coin Control Features</translation> + </message> + <message> + <source>Inputs...</source> + <translation>Inputs...</translation> + </message> + <message> + <source>automatically selected</source> + <translation>automatically selected</translation> + </message> + <message> + <source>Insufficient funds!</source> + <translation>Insufficient funds!</translation> + </message> + <message> + <source>Quantity:</source> + <translation>Quantity:</translation> + </message> + <message> + <source>Bytes:</source> + <translation>Bytes:</translation> + </message> + <message> + <source>Amount:</source> + <translation>Amount:</translation> + </message> + <message> + <source>Fee:</source> + <translation>Fee:</translation> + </message> + <message> + <source>After Fee:</source> + <translation>After Fee:</translation> + </message> + <message> + <source>Change:</source> + <translation>Change:</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>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</translation> + </message> + <message> + <source>Custom change address</source> + <translation>Custom change address</translation> + </message> + <message> + <source>Transaction Fee:</source> + <translation>Transaction Fee:</translation> + </message> + <message> + <source>Choose...</source> + <translation>Choose...</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>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.</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</source> + <translation>Warning: Fee estimation is currently not possible.</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> + <message> + <source>Hide</source> + <translation>Hide</translation> + </message> + <message> + <source>Recommended:</source> + <translation>Recommended:</translation> + </message> + <message> + <source>Custom:</source> + <translation>Custom:</translation> + </message> + <message> + <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> + <translation>(Smart fee not initialized yet. This usually takes a few blocks...)</translation> + </message> + <message> + <source>Send to multiple recipients at once</source> + <translation>Send to multiple recipients at once</translation> + </message> + <message> + <source>Add &Recipient</source> + <translation>Add &Recipient</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Clear all fields of the form.</translation> + </message> + <message> + <source>Dust:</source> + <translation>Dust:</translation> + </message> + <message> + <source>Hide transaction fee settings</source> + <translation>Hide transaction fee settings</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>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.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>A too low fee might result in a never confirming transaction (read the tooltip)</translation> + </message> + <message> + <source>Confirmation time target:</source> + <translation>Confirmation time target:</translation> + </message> + <message> + <source>Enable Replace-By-Fee</source> + <translation>Enable 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>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.</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> <source>Balance:</source> <translation>Baki</translation> </message> <message> + <source>Confirm the send action</source> + <translation>Confirm the send action</translation> + </message> + <message> + <source>S&end</source> + <translation>S&end</translation> + </message> + <message> + <source>Copy quantity</source> + <translation>Copy quantity</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy fee</source> + <translation>Copy fee</translation> + </message> + <message> + <source>Copy after fee</source> + <translation>Copy after fee</translation> + </message> + <message> + <source>Copy bytes</source> + <translation>Copy bytes</translation> + </message> + <message> + <source>Copy dust</source> + <translation>Copy dust</translation> + </message> + <message> + <source>Copy change</source> + <translation>Copy change</translation> + </message> + <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 blocks)</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation>Cr&eate Unsigned</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation> from wallet '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 to '%2'</translation> + </message> + <message> + <source>%1 to %2</source> + <translation>%1 to %2</translation> + </message> + <message> + <source>Do you want to draft this transaction?</source> + <translation>Do you want to draft this transaction?</translation> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation>Are you sure you want to send?</translation> + </message> + <message> + <source>or</source> + <translation>or</translation> + </message> + <message> + <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> + <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</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> + <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Not signalling Replace-By-Fee, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Total Amount</translation> + </message> + <message> + <source>To review recipient list click "Show Details..."</source> + <translation>To review recipient list click "Show Details..."</translation> + </message> + <message> + <source>Confirm send coins</source> + <translation>Confirm send coins</translation> + </message> + <message> + <source>Confirm transaction proposal</source> + <translation>Confirm transaction proposal</translation> + </message> + <message> + <source>Send</source> + <translation>Send</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Watch-only balance:</translation> + </message> + <message> + <source>The recipient address is not valid. Please recheck.</source> + <translation>The recipient address is not valid. Please recheck.</translation> + </message> + <message> + <source>The amount to pay must be larger than 0.</source> + <translation>The amount to pay must be larger than 0.</translation> + </message> + <message> + <source>The amount exceeds your balance.</source> + <translation>The amount exceeds your balance.</translation> + </message> + <message> + <source>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation>The total exceeds your balance when the %1 transaction fee is included.</translation> + </message> + <message> + <source>Duplicate address found: addresses should only be used once each.</source> + <translation>Duplicate address found: addresses should only be used once each.</translation> + </message> + <message> + <source>Transaction creation failed!</source> + <translation>Transaction creation failed!</translation> + </message> + <message> + <source>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>A fee higher than %1 is considered an absurdly high fee.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Payment request expired.</translation> + </message> + <message> + <source>Warning: Invalid Bitcoin address</source> + <translation>Warning: Invalid Bitcoin address</translation> + </message> + <message> + <source>Warning: Unknown change address</source> + <translation>Warning: Unknown change address</translation> + </message> + <message> + <source>Confirm custom change address</source> + <translation>Confirm custom change address</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>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?</translation> + </message> + <message> <source>(no label)</source> <translation>(tiada label)</translation> </message> </context> <context> <name>SendCoinsEntry</name> - </context> + <message> + <source>A&mount:</source> + <translation>A&mount:</translation> + </message> + <message> + <source>Pay &To:</source> + <translation>Pay &To:</translation> + </message> + <message> + <source>&Label:</source> + <translation>&Label:</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Choose previously used address</translation> + </message> + <message> + <source>The Bitcoin address to send the payment to</source> + <translation>The Bitcoin address to send the payment to</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Remove this entry</source> + <translation>Remove this entry</translation> + </message> + <message> + <source>The amount to send in the selected unit</source> + <translation>The amount to send in the selected unit</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>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.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation>S&ubtract fee from amount</translation> + </message> + <message> + <source>Use available balance</source> + <translation>Use available balance</translation> + </message> + <message> + <source>Message:</source> + <translation>Message:</translation> + </message> + <message> + <source>This is an unauthenticated payment request.</source> + <translation>This is an unauthenticated payment request.</translation> + </message> + <message> + <source>This is an authenticated payment request.</source> + <translation>This is an authenticated payment request.</translation> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation>Enter a label for this address to add it to the list of used addresses</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>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.</translation> + </message> + <message> + <source>Pay To:</source> + <translation>Pay To:</translation> + </message> + <message> + <source>Memo:</source> + <translation>Memo:</translation> + </message> +</context> <context> <name>ShutdownWindow</name> - </context> + <message> + <source>%1 is shutting down...</source> + <translation>%1 is shutting down...</translation> + </message> + <message> + <source>Do not shut down the computer until this window disappears.</source> + <translation>Do not shut down the computer until this window disappears.</translation> + </message> +</context> <context> <name>SignVerifyMessageDialog</name> - </context> + <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Signatures - Sign / Verify a Message</translation> + </message> + <message> + <source>&Sign Message</source> + <translation>&Sign Message</translation> + </message> + <message> + <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> + <translation>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.</translation> + </message> + <message> + <source>The Bitcoin address to sign the message with</source> + <translation>The Bitcoin address to sign the message with</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Choose previously used address</translation> + </message> + <message> + <source>Alt+A</source> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Paste address from clipboard</translation> + </message> + <message> + <source>Alt+P</source> + <translation>Alt+P</translation> + </message> + <message> + <source>Enter the message you want to sign here</source> + <translation>Enter the message you want to sign here</translation> + </message> + <message> + <source>Signature</source> + <translation>Signature</translation> + </message> + <message> + <source>Copy the current signature to the system clipboard</source> + <translation>Copy the current signature to the system clipboard</translation> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation>Sign the message to prove you own this Bitcoin address</translation> + </message> + <message> + <source>Sign &Message</source> + <translation>Sign &Message</translation> + </message> + <message> + <source>Reset all sign message fields</source> + <translation>Reset all sign message fields</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Clear &All</translation> + </message> + <message> + <source>&Verify Message</source> + <translation>&Verify Message</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>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!</translation> + </message> + <message> + <source>The Bitcoin address the message was signed with</source> + <translation>The Bitcoin address the message was signed with</translation> + </message> + <message> + <source>The signed message to verify</source> + <translation>The signed message to verify</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>The signature given when the message was signed</translation> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation>Verify the message to ensure it was signed with the specified Bitcoin address</translation> + </message> + <message> + <source>Verify &Message</source> + <translation>Verify &Message</translation> + </message> + <message> + <source>Reset all verify message fields</source> + <translation>Reset all verify message fields</translation> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation>Click "Sign Message" to generate signature</translation> + </message> + <message> + <source>The entered address is invalid.</source> + <translation>The entered address is invalid.</translation> + </message> + <message> + <source>Please check the address and try again.</source> + <translation>Please check the address and try again.</translation> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation>The entered address does not refer to a key.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation>Wallet unlock was cancelled.</translation> + </message> + <message> + <source>No error</source> + <translation>No error</translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation>Private key for the entered address is not available.</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Message signing failed.</translation> + </message> + <message> + <source>Message signed.</source> + <translation>Message signed.</translation> + </message> + <message> + <source>The signature could not be decoded.</source> + <translation>The signature could not be decoded.</translation> + </message> + <message> + <source>Please check the signature and try again.</source> + <translation>Please check the signature and try again.</translation> + </message> + <message> + <source>The signature did not match the message digest.</source> + <translation>The signature did not match the message digest.</translation> + </message> + <message> + <source>Message verification failed.</source> + <translation>Message verification failed.</translation> + </message> + <message> + <source>Message verified.</source> + <translation>Message verified.</translation> + </message> +</context> <context> <name>TrafficGraphWidget</name> - </context> + <message> + <source>KB/s</source> + <translation>KB/s</translation> + </message> +</context> <context> <name>TransactionDesc</name> <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>conflicted with a transaction with %1 confirmations</source> + <translation>conflicted with a transaction with %1 confirmations</translation> + </message> + <message> + <source>0/unconfirmed, %1</source> + <translation>0/unconfirmed, %1</translation> + </message> + <message> + <source>in memory pool</source> + <translation>in memory pool</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>not in memory pool</translation> + </message> + <message> + <source>abandoned</source> + <translation>abandoned</translation> + </message> + <message> + <source>%1/unconfirmed</source> + <translation>%1/unconfirmed</translation> + </message> + <message> + <source>%1 confirmations</source> + <translation>%1 confirmations</translation> + </message> + <message> + <source>Status</source> + <translation>Status</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Source</source> + <translation>Source</translation> + </message> + <message> + <source>Generated</source> + <translation>Generated</translation> + </message> + <message> + <source>From</source> + <translation>From</translation> + </message> + <message> + <source>unknown</source> + <translation>unknown</translation> + </message> + <message> + <source>To</source> + <translation>To</translation> + </message> + <message> + <source>own address</source> + <translation>own address</translation> + </message> + <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> + <source>label</source> + <translation>label</translation> + </message> + <message> + <source>Credit</source> + <translation>Credit</translation> + </message> + <message> + <source>not accepted</source> + <translation>not accepted</translation> + </message> + <message> + <source>Debit</source> + <translation>Debit</translation> + </message> + <message> + <source>Total debit</source> + <translation>Total debit</translation> + </message> + <message> + <source>Total credit</source> + <translation>Total credit</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>Transaction fee</translation> + </message> + <message> + <source>Net amount</source> + <translation>Net amount</translation> + </message> + <message> + <source>Message</source> + <translation>Message</translation> + </message> + <message> + <source>Comment</source> + <translation>Comment</translation> + </message> + <message> + <source>Transaction ID</source> + <translation>Transaction ID</translation> + </message> + <message> + <source>Transaction total size</source> + <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> + <message> + <source> (Certificate was not verified)</source> + <translation> (Certificate was not verified)</translation> + </message> + <message> + <source>Merchant</source> + <translation>Merchant</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>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.</translation> + </message> + <message> + <source>Debug information</source> + <translation>Debug information</translation> + </message> + <message> + <source>Transaction</source> + <translation>Transaction</translation> + </message> + <message> + <source>Inputs</source> + <translation>Inputs</translation> + </message> + <message> <source>Amount</source> <translation>Amount</translation> </message> - </context> + <message> + <source>true</source> + <translation>true</translation> + </message> + <message> + <source>false</source> + <translation>false</translation> + </message> +</context> <context> <name>TransactionDescDialog</name> - </context> + <message> + <source>This pane shows a detailed description of the transaction</source> + <translation>This pane shows a detailed description of the transaction</translation> + </message> + <message> + <source>Details for %1</source> + <translation>Details for %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Type</source> + <translation>Type</translation> + </message> + <message> <source>Label</source> <translation>Label</translation> </message> <message> + <source>Open until %1</source> + <translation>Open until %1</translation> + </message> + <message> + <source>Unconfirmed</source> + <translation>Unconfirmed</translation> + </message> + <message> + <source>Abandoned</source> + <translation>Abandoned</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation>Confirming (%1 of %2 recommended confirmations)</translation> + </message> + <message> + <source>Confirmed (%1 confirmations)</source> + <translation>Confirmed (%1 confirmations)</translation> + </message> + <message> + <source>Conflicted</source> + <translation>Conflicted</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation>Immature (%1 confirmations, will be available after %2)</translation> + </message> + <message> + <source>Generated but not accepted</source> + <translation>Generated but not accepted</translation> + </message> + <message> + <source>Received with</source> + <translation>Received with</translation> + </message> + <message> + <source>Received from</source> + <translation>Received from</translation> + </message> + <message> + <source>Sent to</source> + <translation>Sent to</translation> + </message> + <message> + <source>Payment to yourself</source> + <translation>Payment to yourself</translation> + </message> + <message> + <source>Mined</source> + <translation>Mined</translation> + </message> + <message> + <source>watch-only</source> + <translation>watch-only</translation> + </message> + <message> + <source>(n/a)</source> + <translation>(n/a)</translation> + </message> + <message> <source>(no label)</source> <translation>(tiada label)</translation> </message> - </context> + <message> + <source>Transaction status. Hover over this field to show number of confirmations.</source> + <translation>Transaction status. Hover over this field to show number of confirmations.</translation> + </message> + <message> + <source>Date and time that the transaction was received.</source> + <translation>Date and time that the transaction was received.</translation> + </message> + <message> + <source>Type of transaction.</source> + <translation>Type of transaction.</translation> + </message> + <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Whether or not a watch-only address is involved in this transaction.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>User-defined intent/purpose of the transaction.</translation> + </message> + <message> + <source>Amount removed from or added to balance.</source> + <translation>Amount removed from or added to balance.</translation> + </message> +</context> <context> <name>TransactionView</name> <message> + <source>All</source> + <translation>All</translation> + </message> + <message> + <source>Today</source> + <translation>Today</translation> + </message> + <message> + <source>This week</source> + <translation>This week</translation> + </message> + <message> + <source>This month</source> + <translation>This month</translation> + </message> + <message> + <source>Last month</source> + <translation>Last month</translation> + </message> + <message> + <source>This year</source> + <translation>This year</translation> + </message> + <message> + <source>Range...</source> + <translation>Range...</translation> + </message> + <message> + <source>Received with</source> + <translation>Received with</translation> + </message> + <message> + <source>Sent to</source> + <translation>Sent to</translation> + </message> + <message> + <source>To yourself</source> + <translation>To yourself</translation> + </message> + <message> + <source>Mined</source> + <translation>Mined</translation> + </message> + <message> + <source>Other</source> + <translation>Other</translation> + </message> + <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Enter address, transaction id, or label to search</translation> + </message> + <message> + <source>Min amount</source> + <translation>Min amount</translation> + </message> + <message> + <source>Abandon transaction</source> + <translation>Abandon transaction</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>Increase transaction fee</translation> + </message> + <message> + <source>Copy address</source> + <translation>Copy address</translation> + </message> + <message> + <source>Copy label</source> + <translation>Copy label</translation> + </message> + <message> + <source>Copy amount</source> + <translation>Copy amount</translation> + </message> + <message> + <source>Copy transaction ID</source> + <translation>Copy transaction ID</translation> + </message> + <message> + <source>Copy raw transaction</source> + <translation>Copy raw transaction</translation> + </message> + <message> + <source>Copy full transaction details</source> + <translation>Copy full transaction details</translation> + </message> + <message> + <source>Edit label</source> + <translation>Edit label</translation> + </message> + <message> + <source>Show transaction details</source> + <translation>Show transaction details</translation> + </message> + <message> + <source>Export Transaction History</source> + <translation>Export Transaction History</translation> + </message> + <message> <source>Comma separated file (*.csv)</source> <translation>Fail dibahagi oleh koma(*.csv)</translation> </message> <message> + <source>Confirmed</source> + <translation>Confirmed</translation> + </message> + <message> + <source>Watch-only</source> + <translation>Watch-only</translation> + </message> + <message> + <source>Date</source> + <translation>Date</translation> + </message> + <message> + <source>Type</source> + <translation>Type</translation> + </message> + <message> <source>Label</source> <translation>Label</translation> </message> @@ -612,26 +3059,118 @@ Alihkan fail data ke dalam tab semasa</translation> <translation>Alamat</translation> </message> <message> + <source>ID</source> + <translation>ID</translation> + </message> + <message> <source>Exporting Failed</source> <translation>Mengeksport Gagal</translation> </message> - </context> + <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation>There was an error trying to save the transaction history to %1.</translation> + </message> + <message> + <source>Exporting Successful</source> + <translation>Exporting Successful</translation> + </message> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>The transaction history was successfully saved to %1.</translation> + </message> + <message> + <source>Range:</source> + <translation>Range:</translation> + </message> + <message> + <source>to</source> + <translation>to</translation> + </message> +</context> <context> <name>UnitDisplayStatusBarControl</name> - </context> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Unit to show amounts in. Click to select another unit.</translation> + </message> +</context> <context> <name>WalletController</name> <message> <source>Close wallet</source> <translation>Tutup Wallet</translation> </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Are you sure you wish to close the wallet <i>%1</i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</translation> + </message> </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Create a new wallet</translation> + </message> +</context> <context> <name>WalletModel</name> <message> + <source>Send Coins</source> + <translation>Send Coins</translation> + </message> + <message> + <source>Fee bump error</source> + <translation>Fee bump error</translation> + </message> + <message> + <source>Increasing transaction fee failed</source> + <translation>Increasing transaction fee failed</translation> + </message> + <message> + <source>Do you want to increase the fee?</source> + <translation>Do you want to increase the fee?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Do you want to draft a transaction with fee increase?</translation> + </message> + <message> + <source>Current fee:</source> + <translation>Current fee:</translation> + </message> + <message> + <source>Increase:</source> + <translation>Increase:</translation> + </message> + <message> + <source>New fee:</source> + <translation>New fee:</translation> + </message> + <message> + <source>Confirm fee bump</source> + <translation>Confirm fee bump</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Can't draft transaction.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT copied</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Can't sign transaction.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Could not commit transaction</translation> + </message> + <message> <source>default wallet</source> <translation>dompet lalai </translation> @@ -648,14 +3187,504 @@ Alihkan fail data ke dalam tab semasa</translation> <translation> Alihkan fail data ke dalam tab semasa</translation> </message> - </context> + <message> + <source>Error</source> + <translation>Ralat</translation> + </message> + <message> + <source>Backup Wallet</source> + <translation>Backup Wallet</translation> + </message> + <message> + <source>Wallet Data (*.dat)</source> + <translation>Wallet Data (*.dat)</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>Backup Failed</translation> + </message> + <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation>There was an error trying to save the wallet data to %1.</translation> + </message> + <message> + <source>Backup Successful</source> + <translation>Backup Successful</translation> + </message> + <message> + <source>The wallet data was successfully saved to %1.</source> + <translation>The wallet data was successfully saved to %1.</translation> + </message> + <message> + <source>Cancel</source> + <translation>Cancel</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>Distributed under the MIT software license, see the accompanying file %s or %s</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Prune configured below the minimum of %d MiB. Please use a higher number.</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>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Pruning blockstore...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Unable to start HTTP server. See debug log for details.</translation> + </message> + <message> + <source>The %s developers</source> + <translation>The %s developers</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Cannot obtain a lock on data directory %s. %s is probably already running.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Cannot provide specific connections and have addrman find outgoing connections at the same.</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>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</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> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Please contribute if you find %s useful. Visit %s for further information about the software.</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>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</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>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</translation> + </message> + <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>This is the transaction fee you may discard if change is smaller than dust at this level</translation> + </message> + <message> + <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <translation>Unable to replay blocks. You will need to rebuild the database using -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>Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</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>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation> + </message> + <message> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool must be at least %d MB</translation> + </message> + <message> + <source>Cannot resolve -%s address: '%s'</source> + <translation>Cannot resolve -%s address: '%s'</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>Change index out of range</translation> + </message> + <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Config setting for %s only applied on %s network when in [%s] section.</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Copyright (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation>Corrupted block database detected</translation> + </message> + <message> + <source>Could not find asmap file %s</source> + <translation>Could not find asmap file %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Could not parse asmap file %s</translation> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation>Do you want to rebuild the block database now?</translation> + </message> + <message> + <source>Error initializing block database</source> + <translation>Error initializing block database</translation> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation>Error initializing wallet database environment %s!</translation> + </message> + <message> + <source>Error loading %s</source> + <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> + <message> + <source>Error loading %s: Wallet requires newer version of %s</source> + <translation>Error loading %s: Wallet requires newer version of %s</translation> + </message> + <message> + <source>Error loading block database</source> + <translation>Error loading block database</translation> + </message> + <message> + <source>Error opening block database</source> + <translation>Error opening block database</translation> + </message> + <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> + </message> + <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Failed to rescan the wallet during initialization</translation> + </message> + <message> + <source>Importing...</source> + <translation>Importing...</translation> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>Initialization sanity check failed. %s is shutting down.</translation> + </message> + <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Invalid P2P permission: '%s'</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Invalid amount for -%s=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -discardfee=<amount>: '%s'</source> + <translation>Invalid amount for -discardfee=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> + <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>Unknown address type '%s'</source> + <translation>Unknown address type '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Unknown change type '%s'</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> + <message> + <source>Loading banlist...</source> + <translation>Loading banlist...</translation> + </message> + <message> + <source>Not enough file descriptors available.</source> + <translation>Not enough file descriptors available.</translation> + </message> + <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Prune cannot be configured with a negative value.</translation> + </message> + <message> + <source>Prune mode is incompatible with -txindex.</source> + <translation>Prune mode is incompatible with -txindex.</translation> + </message> + <message> + <source>Replaying blocks...</source> + <translation>Replaying blocks...</translation> + </message> + <message> + <source>Rewinding blocks...</source> + <translation>Rewinding blocks...</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>The source code is available from %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <translation>Transaction fee and change calculation failed</translation> + </message> + <message> + <source>Unable to bind to %s on this computer. %s is probably already running.</source> + <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 logging category %s=%s.</source> + <translation>Unsupported logging category %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Upgrading UTXO database</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>User Agent comment (%s) contains unsafe characters.</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>Verifying blocks...</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Wallet needed to be rewritten: restart %s to complete</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Error: Listening for incoming connections failed (listen returned error %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>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>The transaction amount is too small to send after the fee has been deducted</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>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Error reading from database, shutting down.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Error upgrading chainstate database</translation> + </message> + <message> + <source>Error: Disk space is low for %s</source> + <translation>Error: Disk space is low for %s</translation> + </message> + <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Invalid -onion address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Invalid -proxy address or hostname: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Invalid netmask specified in -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Need to specify a port with -whitebind: '%s'</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Prune mode is incompatible with -blockfilterindex.</translation> + </message> + <message> + <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> + <translation>Reducing -maxconnections from %d to %d, because of system limitations.</translation> + </message> + <message> + <source>Section [%s] is not recognized.</source> + <translation>Section [%s] is not recognized.</translation> + </message> + <message> + <source>Signing transaction failed</source> + <translation>Signing transaction failed</translation> + </message> + <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Specified -walletdir "%s" does not exist</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Specified -walletdir "%s" is a relative path</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Specified -walletdir "%s" is not a directory</translation> + </message> + <message> + <source>The specified config file %s does not exist +</source> + <translation>The specified config file %s does not exist +</translation> + </message> + <message> + <source>The transaction amount is too small to pay the fee</source> + <translation>The transaction amount is too small to pay the fee</translation> + </message> + <message> + <source>This is experimental software.</source> + <translation>This is experimental software.</translation> + </message> + <message> + <source>Transaction amount too small</source> + <translation>Transaction amount too small</translation> + </message> + <message> + <source>Transaction too large</source> + <translation>Transaction too large</translation> + </message> + <message> + <source>Unable to bind to %s on this computer (bind returned error %s)</source> + <translation>Unable to bind to %s on this computer (bind returned error %s)</translation> + </message> + <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>Unable to create the PID file '%s': %s</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>Unable to generate initial keys</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Unknown -blockfilterindex value %s.</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>Verifying wallet(s)...</translation> + </message> + <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Warning: unknown new rules activated (versionbit %i)</translation> + </message> + <message> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation> + </message> + <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>This is the transaction fee you may pay when fee estimates are not available.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s is set very high!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Error loading wallet %s. Duplicate -wallet filename specified.</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>Starting network threads...</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>The wallet will avoid paying less than the minimum relay fee.</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>This is the minimum transaction fee you pay on every transaction.</translation> + </message> + <message> + <source>This is the transaction fee you will pay if you send a transaction.</source> + <translation>This is the transaction fee you will pay if you send a transaction.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <translation>Transaction amounts must not be negative</translation> + </message> + <message> + <source>Transaction has too long of a mempool chain</source> + <translation>Transaction has too long of a mempool chain</translation> + </message> + <message> + <source>Transaction must have at least one recipient</source> + <translation>Transaction must have at least one recipient</translation> + </message> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation>Unknown network specified in -onlynet: '%s'</translation> + </message> + <message> + <source>Insufficient funds</source> + <translation>Insufficient funds</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> + <message> <source>Loading wallet...</source> <translation>Sedang baca wallet...</translation> </message> <message> + <source>Cannot downgrade wallet</source> + <translation>Cannot downgrade wallet</translation> + </message> + <message> + <source>Rescanning...</source> + <translation>Rescanning...</translation> + </message> + <message> <source>Done loading</source> <translation>Baca Selesai</translation> </message> diff --git a/src/qt/locale/bitcoin_my.ts b/src/qt/locale/bitcoin_my.ts index 1b5248ba1a..71fd243c24 100644 --- a/src/qt/locale/bitcoin_my.ts +++ b/src/qt/locale/bitcoin_my.ts @@ -49,6 +49,18 @@ </context> <context> <name>BitcoinGUI</name> + <message> + <source>Error</source> + <translation>အမှား</translation> + </message> + <message> + <source>Warning</source> + <translation>သတိပေးချက်</translation> + </message> + <message> + <source>Information</source> + <translation>အချက်အလက်</translation> + </message> </context> <context> <name>CoinControlDialog</name> @@ -70,6 +82,10 @@ </context> <context> <name>Intro</name> + <message> + <source>Error</source> + <translation>အမှား</translation> + </message> </context> <context> <name>ModalOverlay</name> @@ -82,11 +98,18 @@ </context> <context> <name>OptionsDialog</name> + <message> + <source>Error</source> + <translation>အမှား</translation> + </message> </context> <context> <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -159,6 +182,10 @@ <source>Export the data in the current tab to a file</source> <translation>လက်ရှိ tab မှာရှိတဲ့ဒေတာတွေကို ဖိုင်လ်မှာသိမ်းမယ်။</translation> </message> + <message> + <source>Error</source> + <translation>အမှား</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts index 7119de29ae..82c74c3107 100644 --- a/src/qt/locale/bitcoin_nb.ts +++ b/src/qt/locale/bitcoin_nb.ts @@ -132,6 +132,10 @@ <translation>Repeter passorsetningen</translation> </message> <message> + <source>Show passphrase</source> + <translation>Vis adgangsfrase</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Krypter lommeboken</translation> </message> @@ -172,10 +176,30 @@ <translation>Lommeboken er kryptert</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Angi den nye passordfrasen for lommeboken.<br/> Vennglist du bruker en passordfrase <b> ti eller tilfeldige tegn </b>, eller <b> åtte eller flere ord.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Svriv inn den gamle passfrasen og den nye passordfrasen for lommeboken.</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation>Husk at å kryptere lommeboken ikke vil beskytte dine bitcoins fullstendig fra å bli stjålet av skadevare som infiserer datamaskinen din.</translation> </message> <message> + <source>Wallet to be encrypted</source> + <translation>Lommebok som skal bli kryptert</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Din lommebok er i ferd med å bli kryptert.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Din lommebok er nå kryptert.</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>VIKTIG: Alle tidligere sikkerhetskopier du har tatt av lommebokfilen bør erstattes med den nye krypterte lommebokfilen. Av sikkerhetsgrunner vil tidligere sikkerhetskopier av lommebokfilen bli ubrukelige når du begynner å bruke den ny kypterte lommeboken.</translation> </message> @@ -298,6 +322,14 @@ <translation>Åpne &URI</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Lag lommebok...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Lag en ny lommebok</translation> + </message> + <message> <source>Wallet:</source> <translation>Lommebok:</translation> </message> @@ -446,6 +478,14 @@ <translation>Oppdatert</translation> </message> <message> + <source>Node window</source> + <translation>Nodevindu</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Åpne nodens konsoll for feilsøk og diagnostikk</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&Avsender adresser</translation> </message> @@ -454,6 +494,10 @@ <translation>&Mottaker adresser</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Åpne en bitcoin: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Åpne Lommebok</translation> </message> @@ -514,6 +558,10 @@ <translation>Feil: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation>Advarsel: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>Dato: %1 @@ -577,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Lommeboken er <b>kryptert</b> og for tiden <b>låst</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>En fatal feil har inntruffet. Bitcoin kan ikke lenger trygt fortsette, og må derfor avslutte.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -735,10 +779,58 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Lager lommebok <b>%1<b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Lage lommebok feilet</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Lag lommebokvarsel</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Lag lommebok</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Lommeboknavn</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Krypter lommeboken. Lommeboken blir kryptert med en passordfrase du velger.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Krypter Lommebok</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Deaktiver private nøkler for denne lommeboken. Lommebøker med private nøkler er deaktivert vil ikke ha noen private nøkler og kan ikke ha en HD seed eller importerte private nøkler. Dette er ideelt for loomebøker som kun er klokker.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Deaktiver Private Nøkler</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Lag en tom lommebok. Tomme lommebøker har i utgangspunktet ikke private nøkler eller skript. Private nøkler og adresser kan importeres, eller et HD- frø kan angis på et senere tidspunkt.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Lag Tom Lommebok</translation> + </message> + <message> + <source>Create</source> + <translation>Opprett</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -782,6 +874,10 @@ <translation>Adresse "%1" eksisterer allerede som en mottaksadresse merket "%2" og kan derfor ikke bli lagt til som en sendingsadresse.</translation> </message> <message> + <source>The entered address "%1" is already in the address book with label "%2".</source> + <translation>Den oppgitte adressen ''%1'' er allerede i adresseboken med etiketten ''%2''.</translation> + </message> + <message> <source>Could not unlock wallet.</source> <translation>Kunne ikke låse opp lommebok.</translation> </message> @@ -847,6 +943,10 @@ <translation>Når du klikker OK, vil %1 starte nedlasting og behandle hele den %4 blokkjeden (%2GB) fra de eldste transaksjonene i %3 når %4 først startet.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Gjenoppretting av denne innstillingen krever at du laster ned hele blockchain på nytt. Det er raskere å laste ned hele kjeden først og beskjære den senere Deaktiver noen avanserte funksjoner.</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>Den initielle synkroniseringen er svært krevende, og kan forårsake problemer med maskinvaren i datamaskinen din som du tidligere ikke merket. Hver gang du kjører %1 vil den fortsette nedlastingen der den sluttet.</translation> </message> @@ -867,6 +967,10 @@ <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Kast blokker etter bekreftelse, bortsett fra de siste %1 GB (sviske)</translation> + </message> + <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <translation>Minst %1 GB data vil bli lagret i denne mappen og den vil vokse over tid.</translation> </message> @@ -945,10 +1049,26 @@ <source>Hide</source> <translation>Skjul</translation> </message> - </context> + <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 synkroniseres for øyeblikket. Den vil laste ned overskrifter og blokker fra jevnaldrende og validere dem til de når spissen av blokkjeden.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Ukjent.Synkroniser overskrifter (%1,%2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Åpne bitcoin URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -956,6 +1076,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Åpne lommebok feilet</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Advasel om åpen lommebok.</translation> + </message> + <message> <source>default wallet</source> <translation>standard lommebok</translation> </message> @@ -999,10 +1127,6 @@ <translation>Viser hvorvidt angitt SOCKS5-mellomtjener blir brukt for å nå noder via denne nettverkstypen.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Bruk egen SOCKS&5-proxy for å nå noder via Tor hidden services:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Skjul ikonet fra systemkurven.</translation> </message> @@ -1039,10 +1163,22 @@ <translation>&Nettverk</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>Deaktiver noen avanserte funksjoner, men alle blokker vil fortsatt være fullglyldig. Gjenoppretting av denne innstillingen krever at du laster ned hele blockchain på nytt. Faktisk diskbruk kan være noe høvere.</translation> + </message> + <message> + <source>Prune &block storage to</source> + <translation>Beskjær og blokker lagring til</translation> + </message> + <message> <source>GB</source> <translation>GB</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain.</source> + <translation>Gjenoppretting av denne innstillingen krever at du laster ned hele blockchain på nytt</translation> + </message> + <message> <source>MiB</source> <translation>MiB</translation> </message> @@ -1123,10 +1259,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Koble til Bitcoin-nettverket gjennom en separat SOCKS5 mellomtjener for Tor skjulte tjenester.</translation> - </message> - <message> <source>&Window</source> <translation>&Vindu</translation> </message> @@ -1171,6 +1303,10 @@ <translation>Tredjepart transaksjon URLer</translation> </message> <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Alternativer som er satt i denne dialogboksen overstyres av kommandolinjen eller i konfigurasjonsfilen:</translation> + </message> + <message> <source>&OK</source> <translation>&OK</translation> </message> @@ -1297,7 +1433,22 @@ <source>Current total balance in watch-only addresses</source> <translation>Nåværende totale balanse i kun observerbare adresser</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Totalbeløp</translation> + </message> + <message> + <source>or</source> + <translation>eller</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1313,6 +1464,22 @@ <translation>URI-håndtering</translation> </message> <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin: //' er ikke en gyldig URI. Bruk 'bitcoin:' i stedet.</translation> + </message> + <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Kan ikke behandle betalingsforespørsel fordi BIP70 ikke støttes.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>På grunn av utbredte sikkerhetsfeil i BIP70 anbefales det på det sterkeste at alle selgerinstruksjoner for å bytte lommebok ignoreres.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Hvis du mottar denne feilen, bør du be selgeren gi en BIP21-kompatibel URI.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>Ugyldig betalingsadresse %1</translation> </message> @@ -1470,6 +1637,10 @@ <translation>Feil ved koding av URI til QR-kode.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>Støtte for QR kode ikke tilgjengelig.</translation> + </message> + <message> <source>Save QR Code</source> <translation>Lagre QR-kode</translation> </message> @@ -1505,6 +1676,10 @@ <translation>Datamappe</translation> </message> <message> + <source>Blocksdir</source> + <translation>Blocksdir</translation> + </message> + <message> <source>Startup time</source> <translation>Oppstartstidspunkt</translation> </message> @@ -1525,10 +1700,6 @@ <translation>Blokkjeden</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Nåværende antall blokker</translation> - </message> - <message> <source>Memory Pool</source> <translation>Hukommelsespulje</translation> </message> @@ -1573,10 +1744,6 @@ <translation>Velg en node for å vise detaljert informasjon.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Hvitelistet</translation> - </message> - <message> <source>Direction</source> <translation>Retning</translation> </message> @@ -1597,10 +1764,22 @@ <translation>Synkroniserte Blokker</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Det kartlagte autonome systemet som brukes til å diversifisere valg av fagfeller.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Kartlagt AS</translation> + </message> + <message> <source>User Agent</source> <translation>Brukeragent</translation> </message> <message> + <source>Node window</source> + <translation>Nodevindu</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>Åpne %1-feilrettingsloggfila fra gjeldende datamappe. Dette kan ta et par sekunder for store loggfiler.</translation> </message> @@ -1617,10 +1796,6 @@ <translation>Tjenester</translation> </message> <message> - <source>Ban Score</source> - <translation>Ban Poengsum</translation> - </message> - <message> <source>Connection Time</source> <translation>Tilkoblingstid</translation> </message> @@ -1741,6 +1916,14 @@ <translation>Nettverksaktivitet avskrudd</translation> </message> <message> + <source>Executing command without any wallet</source> + <translation>Utfør kommando uten noen lommebok</translation> + </message> + <message> + <source>Executing command using "%1" wallet</source> + <translation>Utfør kommando med lommebok "%1"</translation> + </message> + <message> <source>(node id: %1)</source> <translation>(node id: %1)</translation> </message> @@ -1761,14 +1944,6 @@ <translation>Utgående</translation> </message> <message> - <source>Yes</source> - <translation>Ja</translation> - </message> - <message> - <source>No</source> - <translation>Nei</translation> - </message> - <message> <source>Unknown</source> <translation>Ukjent</translation> </message> @@ -1804,6 +1979,18 @@ <translation>Et valgfritt beløp å etterspørre. La stå tomt eller null for ikke å etterspørre et spesifikt beløp.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>En valgfri etikett for å knytte til den nye mottaksadressen (brukt av deg for å identifisere en faktura). Det er også knyttet til betalingsforespørselen.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>En valgfri melding som er knyttet til betalingsforespørselen og kan vises til avsenderen.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Lag ny mottakeradresse</translation> + </message> + <message> <source>Clear all fields of the form.</source> <translation>Fjern alle felter fra skjemaet.</translation> </message> @@ -1812,6 +1999,14 @@ <translation>Fjern</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>Innfødte segwit-adresser (også kalt Bech32 eller BIP-173) reduserer transaksjonsgebyrene senere og gir bedre beskyttelse mot skrivefeil, men gamle lommebøker støtter dem ikke. Når du ikke har merket av, opprettes en adresse som er kompatibel med eldre lommebøker.</translation> + </message> + <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Generer nativ segwit (Bech32) adresse</translation> + </message> + <message> <source>Requested payments history</source> <translation>Etterspurt betalingshistorikk</translation> </message> @@ -1847,12 +2042,28 @@ <source>Copy amount</source> <translation>Kopier beløp</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Kunne ikke låse opp lommebok.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-kode</translation> + <source>Amount:</source> + <translation>Beløp:</translation> + </message> + <message> + <source>Label:</source> + <translation>Merkelapp:</translation> + </message> + <message> + <source>Message:</source> + <translation>Melding:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Lommebok:</translation> </message> <message> <source>Copy &URI</source> @@ -1874,30 +2085,6 @@ <source>Payment information</source> <translation>Betalingsinformasjon</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adresse</translation> - </message> - <message> - <source>Amount</source> - <translation>Beløp</translation> - </message> - <message> - <source>Label</source> - <translation>Beskrivelse</translation> - </message> - <message> - <source>Message</source> - <translation>Melding</translation> - </message> - <message> - <source>Wallet</source> - <translation>Lommebok</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2001,6 +2188,14 @@ <translation>Advarsel: Gebyroverslag er ikke tilgjengelig for tiden.</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>Spesifiser en tilpasset avgift per kB (1000 byte) av transaksjonens virtuelle størrelse. + +Merk: Siden avgiften er beregnet per byte-basis, vil et gebyr på "100 satoshis per kB" for en transaksjonsstørrelse på 500 byte (halvparten av 1 kB) til slutt gi et gebyr på bare 50 satoshis.</translation> + </message> + <message> <source>per kilobyte</source> <translation>per kilobyte</translation> </message> @@ -2037,6 +2232,18 @@ <translation>Støv:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Skjul innstillinger for transaksjonsgebyr</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Når det er mindre transaksjonsvolum enn plass i blokkene, kan gruvearbeidere så vel som videresende noder håndheve et minimumsgebyr. Å betale bare denne minsteavgiften er helt greit, men vær klar over at dette kan resultere i en aldri bekreftende transaksjon når det er større etterspørsel etter bitcoin-transaksjoner enn nettverket kan behandle.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> + <translation>For lavt gebyr kan føre til en transaksjon som aldri bekreftes (les verktøytips)</translation> + </message> + <message> <source>Confirmation time target:</source> <translation>Bekreftelsestidsmål:</translation> </message> @@ -2097,10 +2304,18 @@ <translation>%1 (%2 blokker)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Cr & eate Usignert</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 til %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Vil du utarbeide denne transaksjonen?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Er du sikker på at du vil sende?</translation> </message> @@ -2129,10 +2344,26 @@ <translation>Totalbeløp</translation> </message> <message> + <source>To review recipient list click "Show Details..."</source> + <translation>For å se gjennom mottakerlisten, klikk "Vis detaljer ..."</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Bekreft forsendelse av mynter</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Bekreft transaksjonsforslaget</translation> + </message> + <message> + <source>Send</source> + <translation>Send</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Kun-observer balanse:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Mottakeradressen er ikke gyldig. Sjekk den igjen.</translation> </message> @@ -2228,6 +2459,10 @@ <translation>Fjern denne oppføringen</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>beløpet som skal sendes inn den valgte enheten.</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>Gebyret vil bli trukket fra beløpet som blir sendt. Mottakeren vil motta mindre bitcoins enn det du skriver inn i beløpsfeltet. Hvis det er valgt flere mottakere, deles gebyret likt.</translation> </message> @@ -2354,6 +2589,14 @@ <translation>Bitcoin-adressen meldingen ble signert med</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Den signerte meldingen for å bekfrefte</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>signaturen som ble gitt da meldingen ble signert</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Verifiser meldingen for å være sikker på at den ble signert av den angitte Bitcoin-adressen</translation> </message> @@ -2386,6 +2629,10 @@ <translation>Opplåsning av lommebok ble avbrutt.</translation> </message> <message> + <source>No error</source> + <translation>Ingen feil</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Privat nøkkel for den angitte adressen er ikke tilgjengelig.</translation> </message> @@ -2560,6 +2807,10 @@ <translation>Utdatainndeks</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(sertifikatet ble ikke bekreftet)</translation> + </message> + <message> <source>Merchant</source> <translation>Forretningsdrivende</translation> </message> @@ -2882,12 +3133,16 @@ <source>Close wallet</source> <translation>Lukk lommebok</translation> </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Å lukke lommeboken for lenge kan føre til at du må synkronisere hele kjeden hvis beskjæring er aktivert.</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Ingen lommebok har blitt lastet inn.</translation> + <source>Create a new wallet</source> + <translation>Lag en ny lommebok</translation> </message> </context> <context> @@ -2909,6 +3164,10 @@ <translation>Ønsker du å øke gebyret?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Vil du utarbeide en transaksjon med gebyrøkning?</translation> + </message> + <message> <source>Current fee:</source> <translation>Nåværede gebyr:</translation> </message> @@ -2925,6 +3184,14 @@ <translation>Bekreft gebyrøkning</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>Kan ikke utarbeide transaksjon.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT kopiert</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Kan ikke signere transaksjon</translation> </message> @@ -2948,6 +3215,10 @@ <translation>Eksporter data i den valgte fliken til en fil</translation> </message> <message> + <source>Error</source> + <translation>Feilmelding</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Sikkerhetskopier lommebok</translation> </message> @@ -2991,10 +3262,6 @@ <translation>Beskjæring: siste lommeboksynkronisering går utenfor beskjærte data. Du må bruke -reindex (laster ned hele blokkjeden igjen for beskjærte noder)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Feil: En fatal intern feil oppstod, se debug.log for detaljer</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Beskjærer blokklageret...</translation> </message> @@ -3055,14 +3322,6 @@ <translation>Advarsel: Vi ser ikke ut til å være i full overenstemmelse med våre likemenn! Du kan trenge å oppgradere, eller andre noder kan trenge å oppgradere.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d av minst 100 blokker har uventet versjon</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s skadet, berging mislyktes</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool må være minst %d MB</translation> </message> @@ -3083,6 +3342,14 @@ <translation>Oppdaget korrupt blokkdatabase</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>Kunne ikke finne asmap filen %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Kunne ikke analysere asmap filen %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Ønsker du å gjenopprette blokkdatabasen nå?</translation> </message> @@ -3263,6 +3530,10 @@ <translation>Må oppgi en port med -whitebind: '%s'</translation> </message> <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Beskjæringsmodus er inkompatibel med -blokkfilterindex.</translation> + </message> + <message> <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> <translation>Reduserer -maxconnections fra %d til %d, pga. systembegrensninger.</translation> </message> @@ -3321,10 +3592,6 @@ <translation>Advarsel: Ukjente nye regler aktivert (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Zapper alle transaksjoner fra lommeboken...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee er satt veldig høyt! Så stort gebyr kan bli betalt ved en enkelt transaksjon.</translation> </message> @@ -3337,10 +3604,6 @@ <translation>Total lengde av nettverks-versionstreng (%i) er over maks lengde (%i). Reduser tallet eller størrelsen av uacomments.</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>Advarsel: Lommeboksfil skadet, data berget! Original %s lagret som %s i %s; hvis din saldo eller transaksjoner er uriktige, bør du gjenopprette fra sikkerhetskopi.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s er satt veldig høyt!</translation> </message> @@ -3385,6 +3648,10 @@ <translation>Utilstrekkelige midler</translation> </message> <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Avgiftsberegning mislyktes. Fallbackfee er deaktivert. Vent et par blokker eller aktiver -fallbackfee.</translation> + </message> + <message> <source>Loading block index...</source> <translation>Laster blokkindeks...</translation> </message> diff --git a/src/qt/locale/bitcoin_ne.ts b/src/qt/locale/bitcoin_ne.ts index 0a291dd95e..c7cb8d2730 100644 --- a/src/qt/locale/bitcoin_ne.ts +++ b/src/qt/locale/bitcoin_ne.ts @@ -55,8 +55,7 @@ </message> <message> <source>&Copy Address</source> - <translation>ठेगाना कपी गर्नुहोस् -</translation> + <translation>ठेगाना कपी गर्नुहोस्</translation> </message> </context> <context> @@ -191,8 +190,7 @@ </message> <message> <source>Copy address</source> - <translation>ठेगाना कपी गर्नुहोस् -</translation> + <translation>ठेगाना कपी गर्नुहोस्</translation> </message> </context> <context> @@ -275,7 +273,10 @@ <source>Current total balance in watch-only addresses</source> <translation>हेर्ने-मात्र ठेगानामा रहेको हालको जम्मा ब्यालेन्स</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + </context> <context> <name>PaymentServer</name> </context> @@ -320,10 +321,6 @@ </context> <context> <name>ReceiveRequestDialog</name> - <message> - <source>Amount</source> - <translation>रकम</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -396,8 +393,7 @@ <name>TransactionView</name> <message> <source>Copy address</source> - <translation>ठेगाना कपी गर्नुहोस् -</translation> + <translation>ठेगाना कपी गर्नुहोस्</translation> </message> </context> <context> @@ -416,8 +412,7 @@ <name>WalletView</name> <message> <source>&Export</source> - <translation>&amp;निर्यात गर्नुहोस् -</translation> + <translation>&amp;निर्यात गर्नुहोस्</translation> </message> <message> <source>Export the data in the current tab to a file</source> @@ -447,10 +442,6 @@ <translation>चेतावनी: हामी हाम्रा सहकर्मीहरूसँग पूर्णतया सहमत छैनौं जस्तो देखिन्छ! तपाईंले अपग्रेड गर्नु पर्ने हुनसक्छ वा अरू नोडहरूले अपग्रेड गर्नु पर्ने हुनसक्छ ।</translation> </message> <message> - <source>%s corrupt, salvage failed</source> - <translation>%s मा क्षति, बचाव विफल भयो</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool कम्तिमा %d MB को हुनुपर्छ ।</translation> </message> diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts index 73c18cd4d8..2cb42a0e39 100644 --- a/src/qt/locale/bitcoin_nl.ts +++ b/src/qt/locale/bitcoin_nl.ts @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Kopieer het geselecteerde adres naar het klembord</translation> + <translation>Kopieer het momenteel geselecteerde adres naar het systeem klembord</translation> </message> <message> <source>&Copy</source> @@ -47,7 +47,7 @@ </message> <message> <source>Choose the address to send coins to</source> - <translation>Kies het adres om munten naar te versturen</translation> + <translation>Kies het adres om de munten naar te versturen</translation> </message> <message> <source>Choose the address to receive coins with</source> @@ -70,8 +70,10 @@ <translation>Dit zijn uw Bitcoinadressen om betalingen mee te verzenden. Controleer altijd het bedrag en het ontvangstadres voordat u uw bitcoins verzendt.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Dit zijn jouw Bitcoin adressen voor het ontvangen van betalingen. Gebruik de 'Nieuwe ontvangst adres maken' knop in de ontvangst tab om een nieuwe adres te maken.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Dit zijn uw Bitcoin adressen voor het ontvangen van betalingen. Gebruik de 'Nieuw ontvangst adres maken' knop in de ontvangst tab om een nieuwe adres te maken. +Ondertekenen is alleen mogelijk met adressen van het type 'legacy'.</translation> </message> <message> <source>&Copy Address</source> @@ -482,6 +484,22 @@ <translation>Bijgewerkt</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Laad PSBT van bestand...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Laad gedeeltelijk ondertekende Bitcoin-transactie</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Laad PSBT van klembord</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Laad gedeeltelijk ondertekende Bitcoin-transactie vanaf het klembord</translation> + </message> + <message> <source>Node window</source> <translation>Nodevenster</translation> </message> @@ -518,10 +536,26 @@ <translation>Portemonnee Sluiten</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Sluit Alle Portemonnees...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Sluit alle portemonnees</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Toon het %1 hulpbericht om een lijst te krijgen met mogelijke Bitcoin commandoregelopties</translation> </message> <message> + <source>&Mask values</source> + <translation>&Maskeer waarden</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Maskeer de waarden op het tabblad Overzicht</translation> + </message> + <message> <source>default wallet</source> <translation>standaard portemonnee</translation> </message> @@ -630,8 +664,12 @@ <translation>Portemonnee is <b>versleuteld</b> en momenteel <b>gesloten</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Een fatale fout heeft zich voorgedaan. Bitcoin kan niet veilig worden verdergezet en wordt afgesloten.</translation> + <source>Original message:</source> + <translation>Origineel bericht:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Er is een fatale fout opgetreden. %1 kan niet langer veilig doorgaan en wordt afgesloten.</translation> </message> </context> <context> @@ -836,6 +874,14 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Maak een lege portemonnee</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Gebruik descriptors voor scriptPubKey-beheer</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Descriptor Portemonnee</translation> + </message> + <message> <source>Create</source> <translation>Creëer</translation> </message> @@ -1140,10 +1186,6 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Toont aan of de aangeleverde standaard SOCKS5 proxy gebruikt wordt om peers te bereiken via dit netwerktype.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Gebruik aparte SOCKS&5-proxy om peers te bereiken via verborgen Tor-diensten:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Verberg het icoon van de systeembalk.</translation> </message> @@ -1276,10 +1318,6 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Maak verbinding met Bitcoinnetwerk door een aparte SOCKS5-proxy voor verborgen diensten van Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Scherm</translation> </message> @@ -1320,6 +1358,14 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Munt controle functies weergeven of niet.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Maak verbinding met het Bitcoin-netwerk via een aparte SOCKS5-proxy voor Tor Onion-services.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Gebruik afzonderlijke SOCKS & 5-proxy om peers te bereiken via Tor Onion-services:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>Transactie-URL's van &derden</translation> </message> @@ -1454,8 +1500,59 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <source>Current total balance in watch-only addresses</source> <translation>Huidige balans in alleen-bekijkbare adressen.</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Privacymodus geactiveerd voor het tabblad Overzicht. Om de waarden te ontmaskeren, schakelt u Instellingen -> Maskeer waarden uit.</translation> + </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialoog</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Signeer Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Zend Tx uit</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Kopieer naar klembord</translation> + </message> + <message> + <source>Save...</source> + <translation>Opslaan...</translation> + </message> + <message> + <source>Close</source> + <translation>Sluiten</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Laden transactie niet gelukt: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Tekenen transactie niet gelukt: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Kon geen inputs meer ondertekenen.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Totaalbedrag</translation> + </message> + <message> + <source>or</source> + <translation>of</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1718,10 +1815,6 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Blokketen</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Huidig aantal blokken</translation> - </message> - <message> <source>Memory Pool</source> <translation>Geheugenpoel</translation> </message> @@ -1766,10 +1859,6 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Selecteer een peer om gedetailleerde informatie te bekijken.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Toegestaan</translation> - </message> - <message> <source>Direction</source> <translation>Directie</translation> </message> @@ -1790,6 +1879,14 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Gesynchroniseerde blokken</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Het in kaart gebrachte autonome systeem dat wordt gebruikt voor het diversifiëren van peer-selectie.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>AS in kaart gebracht.</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> @@ -1814,10 +1911,6 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Diensten</translation> </message> <message> - <source>Ban Score</source> - <translation>Ban score</translation> - </message> - <message> <source>Connection Time</source> <translation>Connectie tijd</translation> </message> @@ -1966,14 +2059,6 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <translation>Uitgaand</translation> </message> <message> - <source>Yes</source> - <translation>Ja</translation> - </message> - <message> - <source>No</source> - <translation>Nee</translation> - </message> - <message> <source>Unknown</source> <translation>Onbekend</translation> </message> @@ -2072,12 +2157,28 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <source>Copy amount</source> <translation>Kopieer bedrag</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Kon de portemonnee niet openen.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-code</translation> + <source>Amount:</source> + <translation>Bedrag:</translation> + </message> + <message> + <source>Label:</source> + <translation>Label:</translation> + </message> + <message> + <source>Message:</source> + <translation>Bericht:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Portemonnee:</translation> </message> <message> <source>Copy &URI</source> @@ -2099,30 +2200,6 @@ Dit is ideaal voor alleen-lezen portommonees.</translation> <source>Payment information</source> <translation>Betalingsinformatie</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adres</translation> - </message> - <message> - <source>Amount</source> - <translation>Bedrag</translation> - </message> - <message> - <source>Label</source> - <translation>Label</translation> - </message> - <message> - <source>Message</source> - <translation>Bericht</translation> - </message> - <message> - <source>Wallet</source> - <translation>Portemonnee</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2370,10 +2447,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Weet u zeker dat u wilt verzenden?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Gelieve je transactie-voorstel te controleren. Dit zal een Partially Signed Bitcoin Transaction (PSBT) maken die je kan kopiëren en dan tekenen met b.v. een offline %1 wallet, of een PSBT-compatibele hardware wallet.</translation> - </message> - <message> <source>or</source> <translation>of</translation> </message> @@ -2410,18 +2483,10 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Bevestig transactievoorstel</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Kopieer PSBT naar klembord</translation> - </message> - <message> <source>Send</source> <translation>Verstuur</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT is gekopieerd</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Alleen-lezen balans:</translation> </message> @@ -3203,12 +3268,16 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>De portemonee te lang gesloten houden kan leiden tot het moeten hersynchroniseren van de hele keten als snoeien aktief is.</translation> </message> -</context> + <message> + <source>Close all wallets</source> + <translation>Sluit alle portemonnees</translation> + </message> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Er is geen portemonnee geladen.</translation> + <source>Create a new wallet</source> + <translation>Nieuwe wallet creëren</translation> </message> </context> <context> @@ -3281,6 +3350,10 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Exporteer de data in de huidige tab naar een bestand</translation> </message> <message> + <source>Error</source> + <translation>Fout</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Portemonnee backuppen</translation> </message> @@ -3324,10 +3397,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Prune: laatste wallet synchronisatie gaat verder terug dan de middels -prune beperkte data. U moet -reindex gebruiken (downloadt opnieuw de gehele blokketen voor een pruned node)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Fout: er is een fout opgetreden, zie debug.log voor details</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Blokopslag prunen...</translation> </message> @@ -3340,10 +3409,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>De %s ontwikkelaars</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Kan geen rest-adres sleutel genereren. Er zijn geen sleutels in de interne sleutelverzameling en ik kan geen sleutels genereren.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Kan geen lock verkrijgen op gegevensmap %s. %s draait waarschijnlijk al.</translation> </message> @@ -3392,14 +3457,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Waarschuwing: Het lijkt erop dat we geen consensus kunnen vinden met onze peers! Mogelijk dient u te upgraden, of andere nodes moeten wellicht upgraden.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d van de laatste 100 blokken hebben een onverwachte versie</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrupt, veiligstellen mislukt</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool moet minstens %d MB zijn</translation> </message> @@ -3524,10 +3581,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>P2P-adressen aan het laden...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Error: Opslagruimte te weinig!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Verbanningslijst aan het laden...</translation> </message> @@ -3710,10 +3763,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Waarschuwing: onbekende nieuwe regels geactiveerd (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Bezig met het zappen van alle transacties van de portemonnee...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee staat zeer hoog! Transactiekosten van deze grootte kunnen worden gebruikt in een enkele transactie.</translation> </message> @@ -3726,10 +3775,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Totale lengte van netwerkversiestring (%i) overschrijdt maximale lengte (%i). Verminder het aantal of grootte van uacomments.</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>Waarschuwing: portemonnee bestand is corrupt, data is veiliggesteld! Originele %s is opgeslagen als %s in %s; als uw balans of transacties incorrect zijn dient u een backup terug te zetten.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s is zeer hoog ingesteld!</translation> </message> @@ -3774,10 +3819,6 @@ Notitie: Omdat de vergoeding per byte wordt gerekend, zal een vergoeding van "10 <translation>Ontoereikend saldo</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>Het is niet mogelijk een non HD split portemonnee te upgraden zonder pre split keypool te ondersteunen. Gebruik -upgradewallet=169900 of -upgradewallet zonder een specifiek versie nummer.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Het inschatten van de vergoeding is gefaald. Fallbackfee is uitgeschakeld. Wacht een aantal blocks of schakel -fallbackfee in.</translation> </message> diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts index 585fa22226..e747fcc5af 100644 --- a/src/qt/locale/bitcoin_pam.ts +++ b/src/qt/locale/bitcoin_pam.ts @@ -341,11 +341,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Maka-<b>encrypt</b> ya ing wallet at kasalukuyan yang maka-<b>locked</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Atin kamalian a milyari. Ali ne magsilbing sumulung pa ing Bitcoin at kailangan na ng tuknang.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -595,6 +591,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -649,10 +648,6 @@ <translation>Block chain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Kasalungsungan bilang dareng blocks</translation> - </message> - <message> <source>Last block time</source> <translation>Tatauling oras na ning block</translation> </message> @@ -691,34 +686,26 @@ <source>Copy amount</source> <translation>Kopyan ing alaga</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>&Kopyan ing address</translation> - </message> - <message> - <source>Address</source> - <translation>Address</translation> - </message> - <message> - <source>Amount</source> - <translation>Alaga</translation> + <source>Could not unlock wallet.</source> + <translation>Ali ya bisang mag-unlock ing wallet</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Label</source> - <translation>Label</translation> + <source>Amount:</source> + <translation>Alaga:</translation> </message> <message> - <source>Message</source> - <translation>Mensayi</translation> + <source>Message:</source> + <translation>Mensayi:</translation> </message> <message> - <source>Wallet</source> - <translation>Wallet</translation> + <source>Copy &Address</source> + <translation>&Kopyan ing address</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1279,6 +1266,10 @@ </context> <context> <name>WalletView</name> + <message> + <source>Error</source> + <translation>Mali</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index c09e0d41ac..1d8d1f89ff 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -67,11 +67,13 @@ </message> <message> <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source> - <translation>Tutaj znajdują się adresy Bitcoin na które wysyłasz płatności. Zawsze sprawdzaj ilość i adres odbiorcy przed wysyłką monet.</translation> + <translation>To są twoje adresy Bitcoin do wysyłania płatności. Zawsze sprawdź kwotę i adres odbiorcy przed wysłaniem monet.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>To są Twoje adresy Bitcoin do otrzymywania płatności. Użyj przycisku "Stwórz nowy adres odbiorczy" w zakładce odbioru żeby stworzyć nowy adres.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>To są twoje adresy Bitcoin do otrzymywania płatności. Użyj przycisku „Utwórz nowy adres odbiorcy” na karcie odbioru, aby utworzyć nowe adresy. +Podpisywanie jest możliwe tylko z adresami typu „legacy”.</translation> </message> <message> <source>&Copy Address</source> @@ -323,7 +325,7 @@ </message> <message> <source>Open &URI...</source> - <translation>Otwórz URI...</translation> + <translation>Otwórz &URI...</translation> </message> <message> <source>Create Wallet...</source> @@ -482,6 +484,30 @@ <translation>Aktualny</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>Wczytaj PSBT z p&liku ..</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Załaduj częściowo podpisaną transakcję Bitcoin</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Wczytaj PSBT do schowka</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Załaduj częściowo podpisaną transakcję Bitcoin ze schowka</translation> + </message> + <message> + <source>Node window</source> + <translation>Okno węzła</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Otwórz konsolę diagnostyczną i debugowanie węzłów</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&Adresy wysyłania</translation> </message> @@ -490,6 +516,10 @@ <translation>&Adresy odbioru</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Otwórz URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Otwórz Portfel</translation> </message> @@ -506,6 +536,14 @@ <translation>Zamknij portfel</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Zamknij wszystkie portfele ...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Zamknij wszystkie portfele</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Pokaż pomoc %1 aby zobaczyć listę wszystkich opcji lnii poleceń.</translation> </message> @@ -618,10 +656,10 @@ <translation>Portfel jest <b>zaszyfrowany</b> i obecnie <b>zablokowany</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Wystąpił krytyczny błąd. Bitcoin nie jest w stanie kontynuować bezpiecznie i zostanie zamknięty.</translation> + <source>Original message:</source> + <translation>Wiadomość oryginalna:</translation> </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -823,6 +861,10 @@ <translation>Stwórz czysty portfel</translation> </message> <message> + <source>Descriptor Wallet</source> + <translation>Portfel deskryptora</translation> + </message> + <message> <source>Create</source> <translation>Stwórz</translation> </message> @@ -1023,7 +1065,7 @@ </message> <message> <source>Unknown...</source> - <translation>Nienznane...</translation> + <translation>Nieznany...</translation> </message> <message> <source>Last block time</source> @@ -1050,6 +1092,14 @@ <translation>Ukryj</translation> </message> <message> + <source>Esc</source> + <translation>Wyjdź</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 jest w trakcie synchronizacji. Trwa pobieranie i weryfikacja nagłówków oraz bloków z sieci w celu uzyskania aktualnego stanu łańcucha.</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Nieznane. Synchronizowanie nagłówków (%1, %2%)...</translation> </message> @@ -1057,6 +1107,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Otwórz URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1115,10 +1169,6 @@ <translation>Pakazuje czy dostarczone domyślne SOCKS5 proxy jest użyte do połączenia z węzłami przez sieć tego typu.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Użyj oddzielnego proxy SOCKS&5 aby osiągnąć węzły w ukrytych usługach Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Ukryj ikonę z zasobnika systemowego.</translation> </message> @@ -1251,10 +1301,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Połącz się z siecią Bitcoin przy pomocy oddzielnego SOCKS5 proxy dla sieci TOR</translation> - </message> - <message> <source>&Window</source> <translation>&Okno</translation> </message> @@ -1429,7 +1475,78 @@ <source>Current total balance in watch-only addresses</source> <translation>Łączna kwota na podglądanych adresach</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Kopiuj do schowka</translation> + </message> + <message> + <source>Save...</source> + <translation>Zapisz ...</translation> + </message> + <message> + <source>Close</source> + <translation>Zamknij</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Nie udało się wczytać transakcji: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Nie udało się podpisać transakcji: %1</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>transakcja</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Nieznany błąd podczas przetwarzania transakcji.</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT skopiowane do schowka</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Zapisz dane transakcji</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT zapisane na dysk.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>Wysyłanie %1 do %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Nie można obliczyć opłaty za transakcję lub łącznej kwoty transakcji.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Opłata transakcyjna:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Łączna wartość</translation> + </message> + <message> + <source>or</source> + <translation>lub</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Transakcja ciągle oczekuje na podpis(y).</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1449,6 +1566,10 @@ <translation>'bitcoin://' nie jest poprawnym URI. Użyj 'bitcoin:'.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Nie można przetworzyć żądania zapłaty z powodu braku wsparcia BIP70.</translation> + </message> + <message> <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> <translation>Z powodu znanych błędów bezpieczeństwa w BIP70 zaleca się ignorować wszelkie polecenie od sprzedawcy dotyczące zmiany portfela.</translation> </message> @@ -1689,10 +1810,6 @@ <translation>Łańcuch bloków</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Aktualna liczba bloków</translation> - </message> - <message> <source>Memory Pool</source> <translation>Memory Pool (obszar pamięci)</translation> </message> @@ -1737,10 +1854,6 @@ <translation>Wybierz węzeł żeby zobaczyć szczegóły.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Biała lista</translation> - </message> - <message> <source>Direction</source> <translation>Kierunek</translation> </message> @@ -1761,10 +1874,22 @@ <translation>Zsynchronizowane bloki</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Zmapowany autonomiczny system (ang. asmap) używany do dywersyfikacji wyboru węzłów.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Zmapowany autonomiczny system (ang. asmap)</translation> + </message> + <message> <source>User Agent</source> <translation>Aplikacja kliencka</translation> </message> <message> + <source>Node window</source> + <translation>Okno węzła</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>Otwórz plik dziennika debugowania %1 z obecnego katalogu z danymi. Może to potrwać kilka sekund przy większych plikach.</translation> </message> @@ -1777,12 +1902,12 @@ <translation>Zwiększ rozmiar czcionki</translation> </message> <message> - <source>Services</source> - <translation>Usługi</translation> + <source>Permissions</source> + <translation>Uprawnienia</translation> </message> <message> - <source>Ban Score</source> - <translation>Punkty karne</translation> + <source>Services</source> + <translation>Usługi</translation> </message> <message> <source>Connection Time</source> @@ -1933,14 +2058,6 @@ <translation>Wyjściowy</translation> </message> <message> - <source>Yes</source> - <translation>Tak</translation> - </message> - <message> - <source>No</source> - <translation>Nie</translation> - </message> - <message> <source>Unknown</source> <translation>Nieznany</translation> </message> @@ -1976,6 +2093,14 @@ <translation>Opcjonalna kwota by zażądać. Zostaw puste lub zero by nie zażądać konkretnej kwoty.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Dodatkowa etykieta powiązana z nowym adresem do odbierania płatności (używanym w celu odnalezienia faktury). Jest również powiązana z żądaniem płatności.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Dodatkowa wiadomość dołączana do żądania zapłaty, która może być odczytana przez płacącego.</translation> + </message> + <message> <source>&Create new receiving address</source> <translation>&Stwórz nowy adres odbiorczy</translation> </message> @@ -2031,56 +2156,56 @@ <source>Copy amount</source> <translation>Kopiuj kwotę</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Kod QR</translation> + <source>Could not unlock wallet.</source> + <translation>Nie można było odblokować portfela.</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Copy &URI</source> - <translation>Kopiuj &URI</translation> + <source>Request payment to ...</source> + <translation>Żądaj płatności od ...</translation> </message> <message> - <source>Copy &Address</source> - <translation>Kopiuj &adres</translation> + <source>Address:</source> + <translation>Adres:</translation> </message> <message> - <source>&Save Image...</source> - <translation>&Zapisz obraz...</translation> + <source>Amount:</source> + <translation>Kwota:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Zażądaj płatności do %1</translation> + <source>Label:</source> + <translation>Etykieta:</translation> </message> <message> - <source>Payment information</source> - <translation>Informacje o płatności</translation> + <source>Message:</source> + <translation>Wiadomość:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Portfel:</translation> </message> <message> - <source>Address</source> - <translation>Adres</translation> + <source>Copy &URI</source> + <translation>Kopiuj &URI</translation> </message> <message> - <source>Amount</source> - <translation>Kwota</translation> + <source>Copy &Address</source> + <translation>Kopiuj &adres</translation> </message> <message> - <source>Label</source> - <translation>Etykieta</translation> + <source>&Save Image...</source> + <translation>&Zapisz obraz...</translation> </message> <message> - <source>Message</source> - <translation>Wiadomość</translation> + <source>Request payment to %1</source> + <translation>Zażądaj płatności do %1</translation> </message> <message> - <source>Wallet</source> - <translation>Portfel</translation> + <source>Payment information</source> + <translation>Informacje o płatności</translation> </message> </context> <context> @@ -2230,6 +2355,10 @@ Uwaga: Ponieważ opłata jest naliczana za każdy bajt, opłata "100 satoshi za <translation>Pył:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Ukryj ustawienia opłat transakcyjnych</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Gdy ilość transakcji jest mniejsza niż ilość miejsca w bloku, górnicy i węzły przekazujące wymagają minimalnej opłaty. Zapłata tylko tej wartości jest dopuszczalna, lecz może skutkować transakcją która nigdy nie zostanie potwierdzona w sytuacji, gdy ilość transakcji przekroczy przepustowość sieci.</translation> </message> @@ -2298,6 +2427,14 @@ Uwaga: Ponieważ opłata jest naliczana za każdy bajt, opłata "100 satoshi za <translation>%1 (%2 bloków)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>&Utwórz niepodpisaną transakcję</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Tworzy częściowo podpisaną transakcję (ang. PSBT) używaną np. offline z portfelem %1 lub z innym portfelem zgodnym z PSBT.</translation> + </message> + <message> <source> from wallet '%1'</source> <translation>z portfela '%1'</translation> </message> @@ -2310,10 +2447,26 @@ Uwaga: Ponieważ opłata jest naliczana za każdy bajt, opłata "100 satoshi za <translation>%1 do %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Czy chcesz zapisać szkic tej transakcji?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Czy na pewno chcesz wysłać?</translation> </message> <message> + <source>Create Unsigned</source> + <translation>Utwórz niepodpisaną transakcję</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Zapisz dane transakcji</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>Zapisano PSBT</translation> + </message> + <message> <source>or</source> <translation>lub</translation> </message> @@ -2346,6 +2499,18 @@ Uwaga: Ponieważ opłata jest naliczana za każdy bajt, opłata "100 satoshi za <translation>Potwierdź wysyłanie monet</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Potwierdź propozycję transakcji</translation> + </message> + <message> + <source>Send</source> + <translation>Wyślij</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Kwota na obserwowanych kontach:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Adres odbiorcy jest nieprawidłowy, proszę sprawić ponownie.</translation> </message> @@ -2441,6 +2606,10 @@ Uwaga: Ponieważ opłata jest naliczana za każdy bajt, opłata "100 satoshi za <translation>Usuń ten wpis</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Kwota do wysłania w wybranej jednostce</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>Opłata zostanie odjęta od kwoty wysyłane.Odbiorca otrzyma mniej niż bitcoins wpisz w polu kwoty. Jeśli wybrano kilku odbiorców, opłata jest podzielona równo.</translation> </message> @@ -2568,6 +2737,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Adres Bitcoin, którym została podpisana wiadomość</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Podpisana wiadomość do weryfikacji</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>Sygnatura podawana przy podpisywaniu wiadomości</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Zweryfikuj wiadomość, aby upewnić się, że została podpisana odpowiednim adresem Bitcoin.</translation> </message> @@ -2600,6 +2777,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Odblokowanie portfela zostało anulowane.</translation> </message> <message> + <source>No error</source> + <translation>Brak błędów</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Klucz prywatny dla podanego adresu nie jest dostępny.</translation> </message> @@ -3106,14 +3287,22 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw </message> <message> <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> - <translation>Zamknięcie portfela na zbyt długo może skutkować konieczność ponownego załadowania całego łańcucha, jeżeli jest włączony pruning.</translation> + <translation>Zamknięcie portfela na zbyt długo może skutkować koniecznością ponownego załadowania całego łańcucha, jeżeli jest włączony pruning.</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Zamknij wszystkie portfele</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Na pewno zamknąć wszystkie portfe?</translation> </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nie załadowano żadnego portfela.</translation> + <source>Create a new wallet</source> + <translation>Stwórz nowy portfel</translation> </message> </context> <context> @@ -3135,6 +3324,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Czy chcesz zwiększyć prowizję?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Czy chcesz zapisać szkic transakcji ze zwiększoną opłatą transakcyjną?</translation> + </message> + <message> <source>Current fee:</source> <translation>Aktualna opłata:</translation> </message> @@ -3151,6 +3344,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Potwierdź zwiększenie opłaty</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>Nie można zapisać szkicu transakcji.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>Skopiowano PSBT</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Nie można podpisać transakcji.</translation> </message> @@ -3174,6 +3375,22 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Eksportuj dane z aktywnej karty do pliku</translation> </message> <message> + <source>Error</source> + <translation>Błąd</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Wczytaj dane transakcji</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PSBT musi być mniejsze niż 100MB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Nie można odczytać PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Kopia zapasowa portfela</translation> </message> @@ -3217,10 +3434,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Prune: ostatnia synchronizacja portfela jest za danymi. Muszisz -reindexować (pobrać cały ciąg bloków ponownie w przypadku przyciętego węzła)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Błąd: Wystąpił fatalny błąd wewnętrzny, sprawdź szczegóły w debug.log</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Przycinanie zapisu bloków...</translation> </message> @@ -3233,10 +3446,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Deweloperzy %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Nie mogę wygenerować adresu reszty. Brak kluczy w wewnętrznym magazynie kluczy i nie można wygenerować żadnych kluczy.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Nie można uzyskać blokady na katalogu z danymi %s. %s najprawdopodobniej jest już uruchomiony.</translation> </message> @@ -3285,14 +3494,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Uwaga: Wygląda na to, że nie ma pełnej zgodności z naszymi węzłami! Możliwe, że potrzebujesz aktualizacji bądź inne węzły jej potrzebują</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d z ostatnich 100 bloków ma nieoczekiwaną wersję</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s uszkodzony, odtworzenie się nie powiodło</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool musi być przynajmniej %d MB</translation> </message> @@ -3317,6 +3518,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Wykryto uszkodzoną bazę bloków</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>Nie można odnaleźć pliku asmap %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Nie można przetworzyć pliku asmap %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Czy chcesz teraz przebudować bazę bloków?</translation> </message> @@ -3361,6 +3570,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Nie udało się ponownie przeskanować portfela podczas inicjalizacji.</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Nie udało się zweryfikować bazy danych</translation> + </message> + <message> <source>Importing...</source> <translation>Importowanie…</translation> </message> @@ -3389,6 +3602,30 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Nieprawidłowa kwota dla -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase: nie powiodło się wykonanie instrukcji weryfikującej bazę danych: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: nie udało się pobrać wersji schematu portfela sqlite: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation>SQLiteDatabase: nie udało się pobrać identyfikatora aplikacji: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase: nie udało się przygotować instrukcji do weryfikacji bazy danych: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase: nie udało się odczytać błędu weryfikacji bazy danych: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase: nieoczekiwany identyfikator aplikacji. Oczekiwano %u, otrzymano %u</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation>Podany folder bloków "%s" nie istnieje. </translation> @@ -3410,10 +3647,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Wczytywanie adresów P2P...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Błąd: Zbyt mało miejsca na dysku!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Ładowanie listy zablokowanych...</translation> </message> @@ -3490,6 +3723,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Musisz przebudować bazę używając parametru -reindex aby wrócić do trybu pełnego. To spowoduje ponowne pobranie całego łańcucha bloków</translation> </message> <message> + <source>Disk space is too low!</source> + <translation>Zbyt mało miejsca na dysku!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Błąd odczytu z bazy danych, wyłączam się.</translation> </message> @@ -3502,6 +3739,10 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Błąd: zbyt mało miejsca na dysku dla %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Błąd: Pula kluczy jest pusta, odwołaj się do puli kluczy.</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Niewłaściwy adres -onion lub nazwa hosta: '%s'</translation> </message> @@ -3596,10 +3837,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Ostrzeżenie: aktywowano nieznane nowe reguły (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Usuwam wszystkie transakcje z portfela...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee ma ustawioną badzo dużą wartość! Tak wysokie opłaty mogą być zapłacone w jednej transakcji.</translation> </message> @@ -3612,10 +3849,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Całkowita długość łańcucha wersji (%i) przekracza maksymalną dopuszczalną długość (%i). Zmniejsz ilość lub rozmiar parametru uacomment.</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>Ostrzeżenie: Odtworzono dane z uszkodzonego pliku portfela! Oryginalny %s został zapisany jako %s w %s; jeśli twoje saldo lub transakcje są niepoprawne powinieneś odtworzyć kopię zapasową.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s jest ustawione bardzo wysoko!</translation> </message> @@ -3660,10 +3893,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw <translation>Niewystarczające środki</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 można zaktualizować portfela rozdzielnego bez HD, bez aktualizacji obsługi podzielonej bazy kluczy. Użyj -upgradewallet = 169900 lub -upgradewallet bez określonej wersji.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Estymacja opłat nieudana. Domyślna opłata jest wyłączona. Poczekaj kilka bloków lub włącz -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_pt.ts b/src/qt/locale/bitcoin_pt.ts index 9fc9170501..4fbdadd059 100644 --- a/src/qt/locale/bitcoin_pt.ts +++ b/src/qt/locale/bitcoin_pt.ts @@ -70,10 +70,6 @@ <translation>Estes são os seus endereços Bitcoin para enviar pagamentos. Verifique sempre o valor e o endereço de receção antes de enviar moedas.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Estes são os endereços Bitcoin para receiver pagamentos. Use o botão "Criar novo endereço para receiver" para crier novo endereço.</translation> - </message> - <message> <source>&Copy Address</source> <translation>&Copiar Endereço</translation> </message> @@ -482,6 +478,18 @@ <translation>Atualizado</translation> </message> <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Carregar transação de Bitcoin parcialmente assinada</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Carregar PSBT da área de transferência...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Carregar transação de Bitcoin parcialmente assinada da área de transferência.</translation> + </message> + <message> <source>Node window</source> <translation>Janela do nó</translation> </message> @@ -518,6 +526,14 @@ <translation>Fechar a carteira</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Fechar todas carteiras...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Fechar todas carteiras.</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Mostrar a mensagem de ajuda %1 para obter uma lista com possíveis opções a usar na linha de comandos.</translation> </message> @@ -630,10 +646,10 @@ <translation>A carteira está <b>encriptada</b> e atualmente <b>bloqueada</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Ocorreu um erro fatal. O Bitcoin não pode continuar com segurança e irá fechar.</translation> + <source>Original message:</source> + <translation>Mensagem original:</translation> </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -1078,7 +1094,7 @@ <name>OpenURIDialog</name> <message> <source>Open bitcoin URI</source> - <translation>Abrir um bitcoin URI</translation> + <translation>Abrir um Bitcoin URI</translation> </message> <message> <source>URI:</source> @@ -1139,10 +1155,6 @@ <translation>Mostra se o padrão fornecido SOCKS5 proxy, está a ser utilizado para alcançar utilizadores participantes através deste tipo de rede.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Utilize um proxy SOCKS&5 separado para alcançar utilizadores participantes através dos serviços ocultos do Tor.</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Esconder o ícone da barra de ferramentas.</translation> </message> @@ -1276,10 +1288,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Ligar à rede Bitcoin através de um proxy SOCKS5 separado para utilizar os serviços ocultos do Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Janela</translation> </message> @@ -1454,6 +1462,130 @@ <source>Current total balance in watch-only addresses</source> <translation>Saldo disponível em endereços de apenas vigiar</translation> </message> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Diálogo</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Assinar transação</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Transmitir transação</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Copiar para área de transferência</translation> + </message> + <message> + <source>Save...</source> + <translation>Salvar...</translation> + </message> + <message> + <source>Close</source> + <translation>Fechar</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Falha ao carregar transação: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Falha ao assinar transação: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Não pode assinar mais nenhuma entrada.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Assinadas entradas %1, mas mais assinaturas ainda são necessárias.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Transação assinada com sucesso. Transação está pronta para ser transmitida.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Erro desconhecido ao processar a transação.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Transação transmitida com sucesso. +ID transação: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Falha ao transmitir a transação: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT copiada para a área de transferência.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Salvar informação de transação</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transação assinada parcialmente (binária) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT salva no disco.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>Envia %1 para %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Incapaz de calcular a taxa de transação ou o valor total da transação.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Paga taxa de transação:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Valor Total</translation> + </message> + <message> + <source>or</source> + <translation>ou</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Transação tem %1 entradas não assinadas.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Transação está com alguma informação faltando sobre as entradas.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Transação continua precisando de assinatura(s).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Porém esta carteira não pode assinar transações.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Porém esta carteira não tem as chaves corretas.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Transação está completamente assinada e pronta para ser transmitida.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Status da transação é desconhecido.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1620,6 +1752,10 @@ <translation>Erro: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Erro ao inicializar configurações: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 ainda não foi fechado em segurança...</translation> </message> @@ -1718,10 +1854,6 @@ <translation>Cadeia de blocos</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Número atual de blocos</translation> - </message> - <message> <source>Memory Pool</source> <translation>Banco de Memória</translation> </message> @@ -1766,10 +1898,6 @@ <translation>Selecione um ponto para ver informação detalhada.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Permitido por si</translation> - </message> - <message> <source>Direction</source> <translation>Direção</translation> </message> @@ -1790,6 +1918,14 @@ <translation>Blocos Sincronizados</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>O sistema autonômo mapeado usado para diversificar a seleção de pares.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapeado como</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> @@ -1810,12 +1946,12 @@ <translation>Aumentar tamanho da letra</translation> </message> <message> - <source>Services</source> - <translation>Serviços</translation> + <source>Permissions</source> + <translation>Permissões</translation> </message> <message> - <source>Ban Score</source> - <translation>Pontuação de Banimento</translation> + <source>Services</source> + <translation>Serviços</translation> </message> <message> <source>Connection Time</source> @@ -1966,14 +2102,6 @@ <translation>Saída</translation> </message> <message> - <source>Yes</source> - <translation>Sim</translation> - </message> - <message> - <source>No</source> - <translation>Não</translation> - </message> - <message> <source>Unknown</source> <translation>Desconhecido</translation> </message> @@ -2072,56 +2200,60 @@ <source>Copy amount</source> <translation>Copiar valor</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Não foi possível desbloquear a carteira.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Não foi possível gerar um novo endereço %1</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Código QR</translation> + <source>Request payment to ...</source> + <translation>Requisitar pagamento para ...</translation> </message> <message> - <source>Copy &URI</source> - <translation>Copiar &URI</translation> + <source>Address:</source> + <translation>Endereço:</translation> </message> <message> - <source>Copy &Address</source> - <translation>Copi&ar Endereço</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>&Guardar Imagem...</translation> + <source>Amount:</source> + <translation>Valor:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Requisitar Pagamento para %1</translation> + <source>Label:</source> + <translation>Legenda:</translation> </message> <message> - <source>Payment information</source> - <translation>Informação de Pagamento</translation> + <source>Message:</source> + <translation>Mensagem:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Carteira:</translation> </message> <message> - <source>Address</source> - <translation>Endereço</translation> + <source>Copy &URI</source> + <translation>Copiar &URI</translation> </message> <message> - <source>Amount</source> - <translation>Valor</translation> + <source>Copy &Address</source> + <translation>Copi&ar Endereço</translation> </message> <message> - <source>Label</source> - <translation>Etiqueta</translation> + <source>&Save Image...</source> + <translation>&Guardar Imagem...</translation> </message> <message> - <source>Message</source> - <translation>Mensagem</translation> + <source>Request payment to %1</source> + <translation>Requisitar Pagamento para %1</translation> </message> <message> - <source>Wallet</source> - <translation>Carteira</translation> + <source>Payment information</source> + <translation>Informação de Pagamento</translation> </message> </context> <context> @@ -2370,8 +2502,20 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <translation>Tem a certeza que deseja enviar?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Por favor, reveja sua proposta de transação. Isto irá produzir uma transação de Bitcoin parcialmente assinada (PSBT)(sigla em inglês) a qual você pode copiar e então assinar com por exemplo uma carteira %1 offiline ou uma carteira de hardware compatível com PSBT</translation> + <source>Create Unsigned</source> + <translation>Criar sem assinatura</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Salvar informação de transação</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transação assinada parcialmente (binária) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT salva</translation> </message> <message> <source>or</source> @@ -2382,6 +2526,10 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <translation>Pode aumentar a taxa depois (sinaliza substituir-por-taxa, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Por favor, reveja sua proposta de transação. Isto irá produzir uma Transação de Bitcoin parcialmente assinada (PSBT, sigla em inglês) a qual você pode salvar ou copiar e então assinar com por exemplo uma carteira %1 offiline ou uma PSBT compatível com carteira de hardware.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Por favor, reveja a sua transação.</translation> </message> @@ -2410,18 +2558,10 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <translation>Confirmar a proposta de transação</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Copiar PSBT para área de transferência</translation> - </message> - <message> <source>Send</source> <translation>Enviar</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT copiado</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Saldo apenas para visualização:</translation> </message> @@ -3203,12 +3343,28 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Fechar a carteira durante demasiado tempo pode resultar em ter de resincronizar a cadeia inteira se pruning estiver ativado.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Fechar todas carteiras.</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Você tem certeza que deseja fechar todas as carteira?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nenhuma carteira foi carregada</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Nenhuma carteira foi carregada +Ir para o arquivo > Abrir carteira para carregar a carteira +- OU -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Criar novo carteira</translation> </message> </context> <context> @@ -3281,6 +3437,30 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <translation>Exportar os dados no separador atual para um ficheiro</translation> </message> <message> + <source>Error</source> + <translation>Erro</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Incapaz de decifrar a PSBT da área de transferência (base64 inválida)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Carregar dados de transação</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Transação parcialmente assinada (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>Arquivo PSBT deve ser menor que 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Incapaz de decifrar a PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Cópia de Segurança da Carteira</translation> </message> @@ -3324,10 +3504,6 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <translation>Poda: a última sincronização da carteira vai além dos dados podados. Precisa de -reindex (descarregar novamente a cadeia de blocos completa em caso de nó podado)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Erro: surgiu um erro fatal interno. Veja o ficheiro debug.log para mais informação</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>A reduzir a blockstore...</translation> </message> @@ -3340,10 +3516,6 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <translation>Os programadores de %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Não é possível gerar uma chave de alterar endereço. Não há chaves na keypool interna e não podem ser geradas nenhumas chaves.</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> @@ -3392,14 +3564,6 @@ Nota: como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por u <translation>Aviso: parece que nós não estamos de acordo com os nossos pontos! Poderá ter que atualizar, ou outros pontos podem ter que ser atualizados.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d dos últimos 100 blocos têm uma versão inesperada</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrompido, a recuperação falhou</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>- máximo do banco de memória deverá ser pelo menos %d MB</translation> </message> @@ -3525,10 +3689,6 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>A carregar endereços de P2P...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Erro: O espaço disponível no disco é demasiado pequeno!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>A carregar a lista de banir...</translation> </message> @@ -3593,6 +3753,14 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>Erro: a escuta de ligações de entrada falhou (escuta devolveu o erro %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s corrompido. Tente usar a ferramenta de carteira bitcoin-wallet para salvar ou restaurar um backup.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Não é possível atualizar uma carteira divida do tipo não-HD sem atualizar para ser compatível com divisão prévia da keypool. Por favor use a versão 169900 ou sem especificar nenhuma versão.</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>Montante inválido para -maxtxfee=<amount>: '%s' (deverá ser, no mínimo, a taxa mínima de propagação de %s, de modo a evitar transações bloqueadas)</translation> </message> @@ -3601,10 +3769,34 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>O montante da transação é demasiado baixo após a dedução da taxa</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Este erro pode ocorrer se a carteira não foi desligada corretamente e foi carregada da ultima vez usando uma compilação com uma versão mais recente da Berkeley DB. Se sim, por favor use o programa que carregou esta carteira da ultima vez.</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Este é a taxa de transação máxima que você paga (em adição à taxa normal) para priorizar evitar gastos parciais sobre seleção de moeda normal.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Transação precisa uma mudança de endereço, mas nós não podemos gerar isto. Por favor chame keypoolrefill primeiro.</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>Necessita reconstruir a base de dados, utilizando -reindex para voltar ao modo sem poda. Isto irá descarregar novamente a cadeia de blocos completa</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Um erro fatal interno occoreu, veja o debug.log para detalhes</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Não é possível ajustar -peerblockfilters sem -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Espaço de disco é muito pouco!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Erro ao ler da base de dados. A encerrar.</translation> </message> @@ -3617,6 +3809,14 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>Erro: espaço em disco demasiado baixo para %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>A keypool esgotou-se, por favor execute primeiro keypoolrefill1</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>A variação da taxa (%s) é menor que a mínima variação de taxa (%s) configurada.</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Endereço -onion ou hostname inválido: '%s'</translation> </message> @@ -3637,6 +3837,10 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>Necessário especificar uma porta com -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Sem servidor de proxy especificado. Use -proxy=<ip> ou -proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>O modo de remoção é incompatível com -blockfilterindex.</translation> </message> @@ -3711,10 +3915,6 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>Aviso: ativadas novas regras desconhecidas (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>A limpar todas as transações da carteira...</translation> - </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 transação.</translation> </message> @@ -3727,10 +3927,6 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>Comprimento total da entrada da versão de rede (%i) excede o comprimento máximo (%i). Reduzir o número ou o tamanho de uacomments.</translation> </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>Atenção: o ficheiro da carteira está corrompido, foram recuperados dados! Original %s guardado como %s em %s; se o seu saldo ou as transações estiverem incorretos, deve fazer o restauro de uma cópia de segurança.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s está demasiado elevado!</translation> </message> @@ -3775,10 +3971,6 @@ A pasta de blocos especificados "%s" não existe.</translation> <translation>Fundos insuficientes</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>Não é possível atualizar uma carteira dividida não-HD sem atualizar para ser compatível com a keypool antes da divisão. Use -upgradewallet=169900 ou -upgradewallet sem especificar nenhuma versão.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Falha na estimativa de taxa. A taxa alternativa de recurso está desativada. Espere alguns blocos ou ative -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index b4ae9eeee5..71b4bd2640 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>Right-click to edit address or label</translation> </message> <message> <source>Create a new address</source> @@ -70,8 +70,10 @@ <translation>Estes são os seus endereços para enviar pagamentos. Sempre cheque a quantia e o endereço do destinatário antes de enviar moedas.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Esses são seus endereços de Bitcoin para receber pagamentos. Utilize o botão Criar novo endereço de recebimento na aba receber para criar um novo endereço</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Estes são seus endereços Bitcoin para receber pagamentos. Use o botão 'Criar novos endereços de recebimento' na barra receber para criar novos endereços. +Somente é possível assinar com endereços do tipo 'legado'.</translation> </message> <message> <source>&Copy Address</source> @@ -482,6 +484,22 @@ <translation>Atualizado</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Carregar 'PSBT' do arquivo...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Carregar Transação de Bitcoin Parcialmente Assinada</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Carregar PSBT da área de transferência...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Carregar Transação de Bitcoin Parcialmente Assinada da área de transferência</translation> + </message> + <message> <source>Node window</source> <translation>Janela do Nó</translation> </message> @@ -518,10 +536,26 @@ <translation>Fechar carteira</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Fechar Todas as Carteiras...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Fechar todas as carteiras</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Mostrar a mensagem de ajuda do %1 para obter uma lista com possíveis opções de linha de comando Bitcoin</translation> </message> <message> + <source>&Mask values</source> + <translation>&Mascarar valores</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Mascarar os valores na barra Resumo</translation> + </message> + <message> <source>default wallet</source> <translation>carteira padrão</translation> </message> @@ -630,8 +664,12 @@ <translation>Carteira está <b>criptografada</b> e atualmente <b>bloqueada</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Um erro fatal ocorreu. Bitcoin não pode continuar em segurança e irá fechar.</translation> + <source>Original message:</source> + <translation>Mensagem original:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Aconteceu um erro fatal. %1 não pode continuar com segurança e será fechado.</translation> </message> </context> <context> @@ -835,6 +873,14 @@ <translation>Criar Carteira Vazia</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Utilize os descritores para gerenciamento do scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Carteira descritora.</translation> + </message> + <message> <source>Create</source> <translation>Criar</translation> </message> @@ -1139,10 +1185,6 @@ <translation>Mostra se o proxy padrão fornecido SOCKS5 é utilizado para encontrar participantes por este tipo de rede.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Use um proxy SOCKS&5 separado para alcançar participantes via serviços ocultos Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Esconder ícone da bandeja do sistema.</translation> </message> @@ -1275,10 +1317,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Conecte-se à rede Bitcoin através de um proxy SOCKS5 separado para utilizar serviços ocultos Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Janela</translation> </message> @@ -1319,6 +1357,14 @@ <translation>Mostrar ou não opções de controle da moeda.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Conectar à rede Bitcoin através de um proxy SOCKS5 separado para serviços Tor onion.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Use um proxy SOCKS&5 separado para alcançar pares via serviços Tor onion:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&URLs de transação de terceiros</translation> </message> @@ -1453,6 +1499,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Balanço total em endereços monitorados</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Modo de privacidade ativado para a barra Resumo. Para revelar os valores, desabilite Configurações->Mascarar valores</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Diálogo</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Assinar Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Transmitir Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Copiar para Área de Transferência</translation> + </message> + <message> + <source>Save...</source> + <translation>Salvar...</translation> + </message> + <message> + <source>Close</source> + <translation>Fechar</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Falhou ao carregar transação: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Falhou ao assinar transação: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Não foi possível assinar mais nenhuma entrada.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Assinou %1 entradas, mas ainda são necessárias mais assinaturas.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Transação assinada com sucesso. Transação está pronta para ser transmitida.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Erro desconhecido ao processar transação.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Transação transmitida com sucesso! ID da Transação: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Transmissão de transação falhou: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT copiada para área de transferência.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Salvar Dados de Transação</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transação Parcialmente Assinada (Binário) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT salvo no disco.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>* Envia %1 para %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Não foi possível calcular a taxa de transação ou quantidade total da transação.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Paga taxa de transação:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Valor total</translation> + </message> + <message> + <source>or</source> + <translation>ou</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Transação possui %1 entradas não assinadas.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Transação está faltando alguma informação sobre entradas.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Transação ainda precisa de assinatura(s).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Mas esta carteira não pode assinar transações.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Mas esta carteira não possui as chaves certas.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Transação está assinada totalmente e pronta para transmitir.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Situação da transação é desconhecida</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1619,6 +1792,10 @@ <translation>Erro: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Erro ao iniciar configurações: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 ainda não terminou com segurança...</translation> </message> @@ -1717,10 +1894,6 @@ <translation>Corrente de blocos</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Quantidade atual de blocos</translation> - </message> - <message> <source>Memory Pool</source> <translation>Pool de Memória</translation> </message> @@ -1765,10 +1938,6 @@ <translation>Selecione um nó para ver informações detalhadas.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Lista branca</translation> - </message> - <message> <source>Direction</source> <translation>Direção</translation> </message> @@ -1789,6 +1958,14 @@ <translation>Blocos Sincronizados</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>O sistema autônomo delineado usado para a diversificação da seleção de pares.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapeado como</translation> + </message> + <message> <source>User Agent</source> <translation>User Agent</translation> </message> @@ -1797,6 +1974,10 @@ <translation>Janela do Nó</translation> </message> <message> + <source>Current block height</source> + <translation>Altura de bloco atual</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>Abrir o arquivo de log de depuração do %1 localizado no diretório atual de dados. Isso pode levar alguns segundos para arquivos de log grandes.</translation> </message> @@ -1809,12 +1990,12 @@ <translation>Aumentar o tamanho da fonte</translation> </message> <message> - <source>Services</source> - <translation>Serviços</translation> + <source>Permissions</source> + <translation>Permissões</translation> </message> <message> - <source>Ban Score</source> - <translation>Pontuação de Banimento</translation> + <source>Services</source> + <translation>Serviços</translation> </message> <message> <source>Connection Time</source> @@ -1862,7 +2043,7 @@ </message> <message> <source>&Network Traffic</source> - <translation>&Tráfico de Rede</translation> + <translation>&Tráfego da Rede</translation> </message> <message> <source>Totals</source> @@ -1930,7 +2111,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>ATENÇÃO: Fraudadores solicitam a usuários que digitem comandos aqui, e assim roubão o conteúdo de suas carteiras. Não utilize este console sem antes conhecer os comandos e seus efeitos.</translation> + <translation>ATENÇÃO: Fraudadores solicitam a usuários que digitem comandos aqui, e assim roubam o conteúdo de suas carteiras. Não utilize este console sem antes conhecer os comandos e seus efeitos.</translation> </message> <message> <source>Network activity disabled</source> @@ -1965,14 +2146,6 @@ <translation>Saída</translation> </message> <message> - <source>Yes</source> - <translation>Sim</translation> - </message> - <message> - <source>No</source> - <translation>Não</translation> - </message> - <message> <source>Unknown</source> <translation>Desconhecido</translation> </message> @@ -2071,56 +2244,60 @@ <source>Copy amount</source> <translation>Copiar quantia</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Não foi possível desbloquear a carteira.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Não foi possível gerar novo endereço %1 </translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Código QR</translation> - </message> - <message> - <source>Copy &URI</source> - <translation>Copiar &URI</translation> + <source>Request payment to ...</source> + <translation>Solicitar pagamento para...</translation> </message> <message> - <source>Copy &Address</source> - <translation>&Copiar Endereço</translation> + <source>Address:</source> + <translation>Endereço:</translation> </message> <message> - <source>&Save Image...</source> - <translation>&Salvar Imagem...</translation> + <source>Amount:</source> + <translation>Quantia:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Pedido de pagamento para %1</translation> + <source>Label:</source> + <translation>Etiqueta:</translation> </message> <message> - <source>Payment information</source> - <translation>Informação do pagamento</translation> + <source>Message:</source> + <translation>Mensagem:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Carteira:</translation> </message> <message> - <source>Address</source> - <translation>Endereço</translation> + <source>Copy &URI</source> + <translation>Copiar &URI</translation> </message> <message> - <source>Amount</source> - <translation>Quantia</translation> + <source>Copy &Address</source> + <translation>&Copiar Endereço</translation> </message> <message> - <source>Label</source> - <translation>Rótulo</translation> + <source>&Save Image...</source> + <translation>&Salvar Imagem...</translation> </message> <message> - <source>Message</source> - <translation>Mensagem</translation> + <source>Request payment to %1</source> + <translation>Pedido de pagamento para %1</translation> </message> <message> - <source>Wallet</source> - <translation>Carteira</translation> + <source>Payment information</source> + <translation>Informação do pagamento</translation> </message> </context> <context> @@ -2369,8 +2546,20 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Tem certeza que deseja enviar?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Por favor, reveja sua proposta de transação. Será produzido uma Transação de Bitcoin Parcialmente Assinada (PSBT) que você pode copiar e assinar com ex: uma carteira %1 offline, ou uma PSBT-compatível hardware wallet.</translation> + <source>Create Unsigned</source> + <translation>Criar Não Assinado</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Salvar Dados de Transação</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Transação Parcialmente Assinada (Binário) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT salvo</translation> </message> <message> <source>or</source> @@ -2381,6 +2570,10 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Você pode aumentar a taxa depois (sinaliza Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Por favor, reveja sua proposta de transação. Será produzido uma Transação de Bitcoin Parcialmente Assinada (PSBT) que você pode copiar e assinar com ex: uma carteira %1 offline, ou uma PSBT-compatível hardware wallet.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Revise a sua transação.</translation> </message> @@ -2409,18 +2602,10 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Confirmar a proposta de transação</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Copiar PSBT para a área de transferência</translation> - </message> - <message> <source>Send</source> <translation>Enviar</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT copiado</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Saldo monitorado:</translation> </message> @@ -3202,12 +3387,26 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Manter a carteira fechada por muito tempo pode resultar na necessidade de ressincronizar a block chain se prune está ativado.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Fechar todas as carteiras</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Tem certeza que quer fechar todas as carteiras?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nenhuma carteira carregada.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Nenhuma carteira foi carregada. Vá para o menu Arquivo > Abrir Carteira para carregar sua Carteira. -OU-</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Criar uma nova carteira</translation> </message> </context> <context> @@ -3280,6 +3479,30 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Exportar os dados da guia atual para um arquivo</translation> </message> <message> + <source>Error</source> + <translation>Erro</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Não foi possível decodificar PSBT da área de transferência (base64 inválido)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Carregar Dados de Transação</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Transação Parcialmente Assinada (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>Arquivo PSBT deve ser menor que 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Não foi possível decodificar PSDBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Backup da carteira</translation> </message> @@ -3323,10 +3546,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Prune: A ultima sincronização da carteira foi além dos dados podados. Você precisa usar -reindex (fazer o download de toda a blockchain novamente no caso de nós com prune)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Erro: Um erro interno fatal ocorreu, veja debug.log para detalhes</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Prunando os blocos existentes...</translation> </message> @@ -3339,10 +3558,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Desenvolvedores do %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Não é possível criar uma chave de endereço de troco. Nenhuma chave disponível na keypool interna e não é possível gerar novas chaves.</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 exclusividade de escrita no endereço %s. O %s provavelmente já está sendo executado.</translation> </message> @@ -3355,6 +3570,10 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Erro ao ler arquivo %s! Todas as chaves privadas foram lidas corretamente, mas os dados de transação ou o livro de endereços podem estar faltando ou incorretos.</translation> </message> <message> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation>Mais de um endereço onion associado é fornecido. Usando %s para automaticamento criar serviço onion Tor.</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Por favor verifique se a data e o horário de seu computador estão corretos. Se o relógio de seu computador estiver incorreto, %s não funcionará corretamente.</translation> </message> @@ -3363,6 +3582,18 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Por favor contribua se você entender que %s é útil. Visite %s para mais informações sobre o software.</translation> </message> <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: Falha ao preparar a confirmação para buscar a versão do programa da carteira sqlite: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>SQLiteDatabase: Falhou em preparar confirmação para buscar a id da aplicação: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <translation>SQLiteDatabase: Desconhecida a versão %d do programa da carteira sqlite. Apenas a versão %d é suportada</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>O banco de dados de blocos contém um bloco que parece ser do futuro. Isso pode ser devido à data e hora do seu computador estarem configuradas incorretamente. Apenas reconstrua o banco de dados de blocos se você estiver certo de que a data e hora de seu computador estão corretas.</translation> </message> @@ -3391,14 +3622,6 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Atenção: Nós não parecemos concordar plenamente com nossos pares! Você pode precisar atualizar ou outros pares podem precisar atualizar.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d dos últimos 100 blocos possuem versão inesperada.</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrompido, recuperação falhou</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool deve ser pelo menos %d MB</translation> </message> @@ -3475,6 +3698,10 @@ Nota: Como a taxa é calculada por byte, uma taxa de "100 satoshis por kB" por <translation>Falha ao escanear novamente a carteira durante a inicialização</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Falha ao verificar a base de dados</translation> + </message> + <message> <source>Importing...</source> <translation>Importando...</translation> </message> @@ -3503,6 +3730,30 @@ 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>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase: Falhou em executar a confirmação para verificar a base de dados: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: Falha ao burscar a versão do programa da carteira sqlite: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation>SQLiteDatabase: Falha ao procurar a id da aplicação: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase: Falhou em preparar confirmação para verificar a base de dados: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase: Falha ao ler o erro de verificação da base de dados: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase: Id da aplicação inesperada. Esperada %u, got %u</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation> Diretório de blocos especificados "%s" não existe.</translation> @@ -3524,10 +3775,6 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>Carregando endereços P2P...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Erro: Espaço em disco está baixo!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Carregando lista de banidos...</translation> </message> @@ -3592,6 +3839,14 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>Erro: Escutar conexões de entrada falhou (vincular retornou erro %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s está corrompido. Tente usar a ferramenta de carteira bitcoin-wallet para salvamento ou restauração de backup.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Não é possível fazer upgrade de uma carteira dividida não HD sem fazer upgrade para ser compatível com a keypool antes da divisão. Use -upgradewallet=169900 ou -upgradewallet sem especificar nenhuma versão.</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>Valor inválido para -maxtxfee=<valor>: '%s' (precisa ser pelo menos a taxa de minrelay de %s para prevenir que a transação nunca seja confirmada)</translation> </message> @@ -3600,10 +3855,34 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>A quantia da transação é muito pequena para mandar depois de deduzida a taxa</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Este erro pode ocorrer se a sua carteira não foi desligada de forma correta e foi recentementa carregada utilizando uma nova versão do Berkeley DB. Se isto ocorreu então por favor utilize a mesma versão na qual esta carteira foi utilizada pela última vez.</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Esta é a taxa máxima de transação que você pode pagar (além da taxa normal) para priorizar a evasão parcial de gastos em vez da seleção regular de moedas.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Transações precisam de um endereço de troco, mas nós não podemos gerá-lo. Por favor, faça um keypoolrefill primeiro.</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>Você precisa reconstruir o banco de dados usando -reindex para sair do modo prune. Isso irá causar o download de todo o blockchain novamente.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Aconteceu um erro interno fatal, veja os detalhes em debug.log</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Não pode definir -peerblockfilters sem -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Espaço em disco muito baixo!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Erro ao ler o banco de dados. Encerrando.</translation> </message> @@ -3616,6 +3895,14 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>Erro: Espaço em disco menor que %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Keypool exaurida, por gentileza execute keypoolrefill primeiro</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Taxa de taxa (%s) é menor que a configuração da taxa de taxa (%s)</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Endereço -onion ou nome do servidor inválido: '%s'</translation> </message> @@ -3636,6 +3923,10 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>Necessário informar uma porta com -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Nenhum servidor proxy especificado. Use -proxy=<ip> ou proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Modo prune é incompatível com o parâmetro -blockfilterindex.</translation> </message> @@ -3710,10 +4001,6 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>Aviso: Novas regras desconhecidas foram ativadas (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Aniquilando todas as transações da carteira...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>A valor especificado de -maxtxfee está muito alto! Taxas grandes assim podem ser atribuidas numa transação única.</translation> </message> @@ -3726,10 +4013,6 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>O tamanho total da string de versão da rede (%i) excede o tamanho máximo (%i). Reduza o número ou tamanho de uacomments.</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>Atenção: Arquivo da carteira corrompido, dados recuperados! Original %s salvo como %s em %s; se seu saldo ou transações estiverem incorretos, você deve restaurar o backup.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s está muito alto!</translation> </message> @@ -3774,10 +4057,6 @@ Diretório de blocos especificados "%s" não existe.</translation> <translation>Saldo insuficiente</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>Não é possível fazer upgrade de uma carteira dividida não HD sem fazer upgrade para ser compatível com a keypool antes da divisão. Use -upgradewallet=169900 ou -upgradewallet sem especificar nenhuma versão.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Falha na estimativa de taxa. Fallbackfee desativada. Espere alguns blocos ou ative -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_ro.ts b/src/qt/locale/bitcoin_ro.ts index 333a191ed3..6adb5cacc1 100644 --- a/src/qt/locale/bitcoin_ro.ts +++ b/src/qt/locale/bitcoin_ro.ts @@ -15,7 +15,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Copiază adresa selectată în clipboard</translation> + <translation>Copiază adresa selectată curent în clipboard</translation> </message> <message> <source>&Copy</source> @@ -27,7 +27,7 @@ </message> <message> <source>Delete the currently selected address from the list</source> - <translation>Şterge adresa selectată din listă</translation> + <translation>Şterge adresa selectată curent din listă</translation> </message> <message> <source>Enter address or label to search</source> @@ -132,6 +132,10 @@ <translation>Repetaţi noua frază de acces</translation> </message> <message> + <source>Show passphrase</source> + <translation>Arată fraza de acces</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Criptare portofel</translation> </message> @@ -172,6 +176,18 @@ <translation>Portofel criptat</translation> </message> <message> + <source>Wallet to be encrypted</source> + <translation>Portofel de criptat</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Portofelul tău urmează să fie criptat.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Protofelul tău este criptat.</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>IMPORTANT: Orice copie de siguranţă făcută anterior portofelului dumneavoastră ar trebui înlocuită cu cea generată cel mai recent, fişier criptat al portofelului. Pentru siguranţă, copiile de siguranţă vechi ale portofelului ne-criptat vor deveni inutile imediat ce veţi începe folosirea noului fişier criptat al portofelului.</translation> </message> @@ -294,6 +310,14 @@ <translation>Deschide &URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Crează portofel...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Crează un portofel nou</translation> + </message> + <message> <source>Wallet:</source> <translation>Portofel:</translation> </message> @@ -442,6 +466,38 @@ <translation>Actualizat</translation> </message> <message> + <source>Node window</source> + <translation>Fereastra nodului</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Deschide consola pentru depanare şi diagnosticare a nodului</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation>&Adresele de destinatie</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Adresele de primire</translation> + </message> + <message> + <source>Open Wallet</source> + <translation>Deschide portofel</translation> + </message> + <message> + <source>Open a wallet</source> + <translation>Deschide un portofel</translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>Inchide portofel...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>Inchide portofel</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Arată mesajul de ajutor %1 pentru a obţine o listă cu opţiunile posibile de linii de comandă Bitcoin</translation> </message> @@ -450,6 +506,10 @@ <translation>portofel implicit</translation> </message> <message> + <source>No wallets available</source> + <translation>Niciun portofel disponibil</translation> + </message> + <message> <source>&Window</source> <translation>&Fereastră</translation> </message> @@ -458,6 +518,14 @@ <translation>Minimizare</translation> </message> <message> + <source>Zoom</source> + <translation>Zoom</translation> + </message> + <message> + <source>Main Window</source> + <translation>Fereastra principală</translation> + </message> + <message> <source>%1 client</source> <translation>Client %1</translation> </message> @@ -474,6 +542,10 @@ <translation>Eroare: %1</translation> </message> <message> + <source>Warning: %1</source> + <translation> Atenționare: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>Data: %1 @@ -526,6 +598,10 @@ <translation>Generarea de chei HD este <b>dezactivata</b></translation> </message> <message> + <source>Private key <b>disabled</b></source> + <translation>Cheia privată <b>dezactivată</b></translation> + </message> + <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>Portofelul este <b>criptat</b> iar în momentul de faţă este <b>deblocat</b></translation> </message> @@ -533,11 +609,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Portofelul este <b>criptat</b> iar în momentul de faţă este <b>blocat</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>A survenit o eroare fatală. Bitcoin nu mai poate continua în siguranţă şi se va opri.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -691,10 +763,46 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Create wallet failed</source> + <translation>Crearea portofelului a eşuat</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Atentionare la crearea portofelului</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Crează portofel</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Numele portofelului</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Criptează portofelul. Portofelul va fi criptat cu fraza de acces aleasă.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Criptează portofelul.</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Dezactivează cheile private pentru acest portofel. Portofelele cu cheile private dezactivate nu vor avea chei private şi nu vor putea avea samanţă HD sau chei private importate. Ideal pentru portofele marcate doar pentru citire.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Dezactivează cheile private</translation> + </message> + <message> + <source>Create</source> + <translation>Creează</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -955,10 +1063,6 @@ <translation>Arata daca proxy-ul SOCKS5 furnizat implicit este folosit pentru a gasi parteneri via acest tip de retea.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Foloseste un proxy SOCKS&5 separat pentru a gasi parteneri via servicii TOR ascunse</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Ascunde icon-ul din system tray.</translation> </message> @@ -1087,10 +1191,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Conectare la reteaua Bitcoin printr-un proxy SOCKS5 separat pentru serviciile TOR ascunse.</translation> - </message> - <message> <source>&Window</source> <translation>&Fereastră</translation> </message> @@ -1261,7 +1361,18 @@ <source>Current total balance in watch-only addresses</source> <translation>Soldul dvs. total în adresele doar-supraveghere</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Suma totală</translation> + </message> + <message> + <source>or</source> + <translation>sau</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1497,10 +1608,6 @@ <translation>Lanţ de blocuri</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Numărul curent de blocuri</translation> - </message> - <message> <source>Memory Pool</source> <translation>Pool Memorie</translation> </message> @@ -1545,10 +1652,6 @@ <translation>Selectaţi un partener pentru a vedea informaţiile detaliate.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Whitelisted</translation> - </message> - <message> <source>Direction</source> <translation>Direcţie</translation> </message> @@ -1573,6 +1676,10 @@ <translation>Agent utilizator</translation> </message> <message> + <source>Node window</source> + <translation>Fereastra nodului</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>Deschide fişierul jurnal depanare %1 din directorul curent. Aceasta poate dura cateva secunde pentru fişierele mai mari.</translation> </message> @@ -1589,10 +1696,6 @@ <translation>Servicii</translation> </message> <message> - <source>Ban Score</source> - <translation>Scor Ban</translation> - </message> - <message> <source>Connection Time</source> <translation>Timp conexiune</translation> </message> @@ -1741,14 +1844,6 @@ <translation>Ieşire</translation> </message> <message> - <source>Yes</source> - <translation>Da</translation> - </message> - <message> - <source>No</source> - <translation>Nu</translation> - </message> - <message> <source>Unknown</source> <translation>Necunoscut</translation> </message> @@ -1835,12 +1930,24 @@ <source>Copy amount</source> <translation>Copiază suma</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Portofelul nu a putut fi deblocat.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Cod QR</translation> + <source>Amount:</source> + <translation>Sumă:</translation> + </message> + <message> + <source>Message:</source> + <translation>Mesaj:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Portofel:</translation> </message> <message> <source>Copy &URI</source> @@ -1862,30 +1969,6 @@ <source>Payment information</source> <translation>Informaţiile plată</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adresă</translation> - </message> - <message> - <source>Amount</source> - <translation>Cantitate</translation> - </message> - <message> - <source>Label</source> - <translation>Etichetă</translation> - </message> - <message> - <source>Message</source> - <translation>Mesaj</translation> - </message> - <message> - <source>Wallet</source> - <translation>Portofel</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2093,6 +2176,10 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>%1(%2 blocuri)</translation> </message> <message> + <source> from wallet '%1'</source> + <translation>din portofelul '%1'</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 la %2</translation> </message> @@ -2556,6 +2643,10 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>Index debit</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(Certificatul nu a fost verificat)</translation> + </message> + <message> <source>Merchant</source> <translation>Comerciant</translation> </message> @@ -2874,12 +2965,16 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o </context> <context> <name>WalletController</name> + <message> + <source>Close wallet</source> + <translation>Inchide portofel</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nu a fost încărcat nici un portofel.</translation> + <source>Create a new wallet</source> + <translation>Crează un portofel nou</translation> </message> </context> <context> @@ -2940,6 +3035,10 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>Exportă datele din tab-ul curent într-un fişier</translation> </message> <message> + <source>Error</source> + <translation>Eroare</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Backup portofelul electronic</translation> </message> @@ -2983,10 +3082,6 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>Reductie: ultima sincronizare merge dincolo de datele reductiei. Trebuie sa faceti -reindex (sa descarcati din nou intregul blockchain in cazul unui nod redus)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Eroare: S-a produs o eroare interna fatala, vedeti debug.log pentru detalii</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Reductie blockstore...</translation> </message> @@ -3047,14 +3142,6 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>Atenţie: Aparent, nu sîntem de acord cu toţi partenerii noştri! Va trebui să faceţi o actualizare, sau alte noduri necesită actualizare.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d din ultimele 100 blocuri a o versiune neasteptata</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corupt, salvare nereuşită</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool trebuie sa fie macar %d MB</translation> </message> @@ -3311,10 +3398,6 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>Atentie: se activeaza reguli noi necunoscute (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Şterge toate tranzacţiile din portofel...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee este setata foarte sus! Se pot plati taxe de aceasta marime pe o singura tranzactie.</translation> </message> @@ -3327,10 +3410,6 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>Lungimea totala a sirului versiunii retelei (%i) depaseste lungimea maxima (%i). Reduceti numarul sa dimensiunea uacomments.</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>Atenţie: fişierul portofelului este corupt, date salvate! Fişierul %s a fost salvat ca %s in %s; dacă balanta sau tranzactiile sunt incorecte ar trebui să restauraţi dintr-o copie de siguranţă.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s este setata foarte sus!</translation> </message> @@ -3375,10 +3454,6 @@ Nota: Cum taxa este calculata per byte, o taxa de "100 satoshi per kB" pentru o <translation>Fonduri insuficiente</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>Nu se poate actualiza un portofel split HD fără a fi actualizat pentru a sprijini keypool-ul pre divizat. Vă rugăm să folosiți -upgradewallet=169900 sau -upgradewallet fără nicio versiune specificată.</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> diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts index b7515b1a7c..ba327643d6 100644 --- a/src/qt/locale/bitcoin_ru.ts +++ b/src/qt/locale/bitcoin_ru.ts @@ -70,8 +70,10 @@ <translation>Это ваши Биткойн-адреса для отправки платежей. Всегда проверяйте количество и адрес получателя перед отправкой перевода.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Это ваши Биткойн-адреса для приёма платежей. Используйте кнопку «Создать новый адрес для получения» на вкладке Получить, чтобы создать новые адреса.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Это ваши Биткойн адреса для получения платежей. Используйте кнопку «Создать новый адрес для получения» на вкладке Получить, чтобы создать новые адреса. +Подписание возможно только с адресами типа "legacy".</translation> </message> <message> <source>&Copy Address</source> @@ -181,7 +183,7 @@ </message> <message> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation>Введите новый пароль для кошелька.<br/>Используйте пароль, состоящий из <b>десяти или более случайных символов</b>, или <b>восьми или более слов</b>.</translation> + <translation>Введите новый пароль для кошелька.<br/>Используйте пароль, состоящий из <b>десяти или более случайных символов</b> или <b>восьми или более слов</b>.</translation> </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> @@ -205,7 +207,7 @@ </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> @@ -399,11 +401,11 @@ </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>Подписывайте сообщения Биткойн-адресами чтобы подтвердить что это написали именно Вы</translation> + <translation>Подписывайте сообщения Биткойн-адресами, чтобы подтвердить, что это написали именно вы</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>Проверяйте сообщения чтобы убедиться что они подписаны конкретными Биткойн-адресами</translation> + <translation>Проверяйте сообщения, чтобы убедиться, что они подписаны конкретными Биткойн-адресами</translation> </message> <message> <source>&File</source> @@ -482,6 +484,30 @@ <translation>Готов</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Загрузить PSBT из файла...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Загрузить Частично Подписанные Биткойн Транзакции (PSBT)</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Загрузить PSBT из буфера обмена...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Загрузить Частично Подписанную Транзакцию из буфера обмена</translation> + </message> + <message> + <source>Node window</source> + <translation>Окно узла</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Открыть консоль отладки и диагностики узла</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&Адреса для отправлений</translation> </message> @@ -490,6 +516,10 @@ <translation>&Адреса для получений</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Открыть биткойн: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Открыть Кошелёк</translation> </message> @@ -506,10 +536,26 @@ <translation>Закрыть кошелёк</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Закрыть все кошельки</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Закрыть все кошельки</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Показать помощь по %1, чтобы получить список доступных параметров командной строки</translation> </message> <message> + <source>&Mask values</source> + <translation>&Скрыть значения</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Скрыть значения на вкладке Обзор</translation> + </message> + <message> <source>default wallet</source> <translation>Кошелёк по умолчанию</translation> </message> @@ -618,8 +664,13 @@ <translation>Кошелёк <b>зашифрован</b> и сейчас <b>заблокирован</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Произошла критическая ошибка. Биткойн больше не может продолжать безопасную работу и будет закрыт.</translation> + <source>Original message:</source> + <translation>Исходное сообщение:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Произошла критическая ошибка. %1 больше не может продолжать безопасную работу и будет закрыт. + </translation> </message> </context> <context> @@ -808,7 +859,7 @@ </message> <message> <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> - <translation>Отключить приватные ключи для этого кошелька. Кошельки с отключенными приватными ключами не будут иметь приватных ключей и HD мастер-ключ или импортированные приватные ключи. Это подходит только кошелькам для часов.</translation> + <translation>Отключить приватные ключи для этого кошелька. Кошельки с отключенными приватными ключами не будут иметь приватных ключей и HD мастер-ключа или импортированных приватных ключей. Это подходит только кошелькам для часов.</translation> </message> <message> <source>Disable Private Keys</source> @@ -816,13 +867,21 @@ </message> <message> <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> - <translation>Сделать пустой кошелёк. Чистые кошельки изначально не имеют приватных ключей или скриптов. Позже можно импортировать приватные ключи и адреса, или установить HD мастер-ключ.</translation> + <translation>Сделать пустой кошелёк. Чистые кошельки изначально не имеют приватных ключей или скриптов. Позже можно импортировать приватные ключи и адреса или установить HD мастер-ключ.</translation> </message> <message> <source>Make Blank Wallet</source> <translation>Создать пустой кошелёк</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Использовать дескриптор для управления scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Дескриптор кошелька</translation> + </message> + <message> <source>Create</source> <translation>Создать</translation> </message> @@ -944,7 +1003,7 @@ </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> @@ -1050,6 +1109,14 @@ <translation>Спрятать</translation> </message> <message> + <source>Esc</source> + <translation>Выйти</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 синхронизировано. Заголовки и блоки будут скачиваться с узлов сети и проверяться до тех пор пока не будет достигнут конец цепи блоков.</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Неизвестно. Синхронизация заголовков (%1, %2%)...</translation> </message> @@ -1057,6 +1124,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Открыть URI биткойна</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1112,11 +1183,7 @@ </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> + <translation>Показывает, используется ли прокси SOCKS5 по умолчанию для доступа к узлам через этот тип сети.</translation> </message> <message> <source>Hide the icon from the system tray.</source> @@ -1132,7 +1199,7 @@ </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-адреса (например, обозреватель блоков) , которые отображаются на вкладке транзакции как элементы контекстного меню. %s в URL заменяется хэшем транзакции. Несколько URL-адресов разделены вертикальной чертой |.</translation> + <translation>Сторонние URL-адреса (например, обозреватель блоков), которые отображаются на вкладке транзакции как элементы контекстного меню. %s в URL заменяется хэшем транзакции. Несколько URL-адресов разделены вертикальной чертой |.</translation> </message> <message> <source>Open the %1 configuration file from the working directory.</source> @@ -1156,7 +1223,7 @@ </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> + <translation>Отключает некоторые дополнительные функции, но все блоки по-прежнему будут полностью проверены. Для возврата к этому параметру необходимо повторно загрузить весь блокчейн. Фактическое использование диска может быть несколько больше.</translation> </message> <message> <source>Prune &block storage to</source> @@ -1192,7 +1259,7 @@ </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>При отключении траты неподтверждённой сдачи, сдача от транзакции не может быть использована до тех пор пока у этой транзакции не будет хотя бы одно подтверждение. Это также влияет как ваш баланс рассчитывается.</translation> + <translation>При отключении траты неподтверждённой сдачи сдача от транзакции не может быть использована до тех пор пока у этой транзакции не будет хотя бы одно подтверждение. Это также влияет как ваш баланс рассчитывается.</translation> </message> <message> <source>&Spend unconfirmed change</source> @@ -1200,7 +1267,7 @@ </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>Автоматически открыть порт для Биткойн-клиента на маршрутизаторе. Работает только если Ваш маршрутизатор поддерживает UPnP, и данная функция включена.</translation> + <translation>Автоматически открыть порт для Биткойн-клиента на маршрутизаторе. Работает, если ваш маршрутизатор поддерживает UPnP, и данная функция включена.</translation> </message> <message> <source>Map port using &UPnP</source> @@ -1216,7 +1283,7 @@ </message> <message> <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> - <translation>Подключится к сети Биткойн через прокси SOCKS5.</translation> + <translation>Подключиться к сети Биткойн через прокси SOCKS5.</translation> </message> <message> <source>&Connect through SOCKS5 proxy (default proxy):</source> @@ -1251,10 +1318,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Подключатся к Биткойн-сети через отдельный прокси SOCKS5 для скрытых сервисов Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Окно</translation> </message> @@ -1295,6 +1358,14 @@ <translation>Показывать ли опцию управления монетами.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Подключаться к Биткойн-сети через отдельный прокси SOCKS5 для скрытых сервисов Tor.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Использовать отдельный прокси SOCKS&5 для соединения с узлами через скрытые сервисы Tor:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&Ссылки на транзакции сторонних сервисов</translation> </message> @@ -1383,7 +1454,7 @@ </message> <message> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> - <translation>Общая сумма всех транзакций, которые до сих пор не подтверждены, и до сих пор не учитываются в расходном балансе</translation> + <translation>Общая сумма всех транзакций, которые до сих пор не подтверждены и не учитываются в расходном балансе</translation> </message> <message> <source>Immature:</source> @@ -1429,6 +1500,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Текущий общий баланс на адресах наблюдения</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Режим приватности включен для вкладки обзора. Чтобы показать данные, отключите настройку Скрыть Значения.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Подписать транзакцию</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Отправить Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Скопировать в буфер обмена</translation> + </message> + <message> + <source>Save...</source> + <translation>Сохранить...</translation> + </message> + <message> + <source>Close</source> + <translation>Закрыть</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Не удалось загрузить транзакцию: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Не удалось подписать транзакцию: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Не удалось подписать оставшиеся входы.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Подписано %1 входов, но требуется больше подписей.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Транзакция успешно подписана. Транзакция готова к отправке.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Неизвестная ошибка во время обработки транзакции.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Транзакция успешно отправлена! ID транзакции: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Отправка транзакции не удалась: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT скопирован в буфер обмена</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Сохранить данные о транзакции</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Частично Подписанная Транзакция (Бинарный файл) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT сохранён на диск.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>* Отправляет %1 к %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Не удалось сосчитать сумму комиссии или общую сумму транзакции.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Платит комиссию:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Общая сумма</translation> + </message> + <message> + <source>or</source> + <translation>или</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Транзакция имеет %1 неподписанных входов.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Транзакция имеет недостаточно информации о некоторых входах.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Транзакция требует по крайней мере одну подпись.</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Но этот кошелёк не может подписывать транзакции.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Но этот кошелёк не имеет необходимые ключи.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Транзакция полностью подписана, и готова к отправке.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Статус транзакции неизвестен.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1446,7 +1644,11 @@ </message> <message> <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> - <translation>'bitcoin://' не верный URI. Используйте 'bitcoin:' вместо этого.</translation> + <translation>'bitcoin://' неверный URI. Используйте 'bitcoin:' вместо этого.</translation> + </message> + <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Невозможно обработать запрос платежа, потому что BIP70 не поддерживается.</translation> </message> <message> <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> @@ -1552,7 +1754,7 @@ </message> <message numerus="yes"> <source>%n week(s)</source> - <translation><numerusform>%n недели</numerusform><numerusform>%n недель</numerusform><numerusform>%n недель</numerusform><numerusform>%n недель</numerusform></translation> + <translation><numerusform>%n неделя</numerusform><numerusform>%n недель</numerusform><numerusform>%n недель</numerusform><numerusform>%n недель</numerusform></translation> </message> <message> <source>%1 and %2</source> @@ -1560,7 +1762,7 @@ </message> <message numerus="yes"> <source>%n year(s)</source> - <translation><numerusform>%n год</numerusform><numerusform>%n лет</numerusform><numerusform>%n лет</numerusform><numerusform>%n лет</numerusform></translation> + <translation><numerusform>%n год</numerusform><numerusform>%n года</numerusform><numerusform>%n лет</numerusform><numerusform>%n лет</numerusform></translation> </message> <message> <source>%1 B</source> @@ -1584,13 +1786,17 @@ </message> <message> <source>Error: Cannot parse configuration file: %1.</source> - <translation>Ошибка : Не возможно разобрать файл конфигурации: %1.</translation> + <translation>Ошибка : Невозможно разобрать файл конфигурации: %1.</translation> </message> <message> <source>Error: %1</source> <translation>Ошибка: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Ошибка инициализации настроек: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 ещё не завершился безопасно...</translation> </message> @@ -1619,7 +1825,7 @@ </message> <message> <source>QR code support not available.</source> - <translation>Поддержка QR кодов не доступна.</translation> + <translation>Поддержка QR кодов недоступна.</translation> </message> <message> <source>Save QR Code</source> @@ -1627,7 +1833,7 @@ </message> <message> <source>PNG Image (*.png)</source> - <translation>PNG Картинка (*.png)</translation> + <translation>PNG Image (*.png)</translation> </message> </context> <context> @@ -1689,10 +1895,6 @@ <translation>Блокчейн</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Текущее количество блоков</translation> - </message> - <message> <source>Memory Pool</source> <translation>Пул памяти</translation> </message> @@ -1737,10 +1939,6 @@ <translation>Выберите пира для просмотра детальной информации.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Белый список</translation> - </message> - <message> <source>Direction</source> <translation>Направление</translation> </message> @@ -1761,10 +1959,26 @@ <translation>Синхронизировано блоков</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>The mapped Autonomous System used for diversifying peer selection.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapped AS</translation> + </message> + <message> <source>User Agent</source> <translation>Пользовательский агент</translation> </message> <message> + <source>Node window</source> + <translation>Окно узла</translation> + </message> + <message> + <source>Current block height</source> + <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> @@ -1777,12 +1991,12 @@ <translation>Увеличить размер шрифта</translation> </message> <message> - <source>Services</source> - <translation>Сервисы</translation> + <source>Permissions</source> + <translation>Права</translation> </message> <message> - <source>Ban Score</source> - <translation>Запретить счёт</translation> + <source>Services</source> + <translation>Сервисы</translation> </message> <message> <source>Connection Time</source> @@ -1870,7 +2084,7 @@ </message> <message> <source>&Disconnect</source> - <translation>&Отключится</translation> + <translation>&Отключиться</translation> </message> <message> <source>Ban for</source> @@ -1882,7 +2096,7 @@ </message> <message> <source>Welcome to the %1 RPC console.</source> - <translation>Добро пожаловать в %1 RPC консоль</translation> + <translation>Добро пожаловать в %1 RPC-консоль</translation> </message> <message> <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> @@ -1894,7 +2108,7 @@ </message> <message> <source>For more information on using this console type %1.</source> - <translation>Для получения дополнительных сведений об использовании этой консоли, введите %1.</translation> + <translation>Для получения дополнительных сведений об использовании этой консоли введите %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> @@ -1933,14 +2147,6 @@ <translation>Исходящий</translation> </message> <message> - <source>Yes</source> - <translation>Да</translation> - </message> - <message> - <source>No</source> - <translation>Нет</translation> - </message> - <message> <source>Unknown</source> <translation>Неизвестно</translation> </message> @@ -1973,7 +2179,15 @@ </message> <message> <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> - <translation>Необязательная сумма для запроса. Оставьте пустым или укажите ноль, чтобы запросить неопределённую сумму.</translation> + <translation>Необязательная сумма для запроса. Оставьте пустым или укажите ноль, чтобы не запрашивать определённую сумму.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Необязательная метка, ассоциированная с новым адресом приёма (используется вами, чтобы идентифицировать выставленный счёт). Также она присоединяется к запросу платежа.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Необязательное сообщение, которое присоединяется к запросу платежа и может быть показано отправителю.</translation> </message> <message> <source>&Create new receiving address</source> @@ -1989,7 +2203,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>"Родные" segwit адреса (Bech32 или BIP-173) в дальнейшем уменьшат комиссии ваших транзакций и предоставят улучшенную защиту от опечаток, однако старые кошельки не поддерживают эти адреса. Если не выбрано, будет создан совместимый со старыми кошелёк.</translation> + <translation>"Родные" segwit-адреса (Bech32 или BIP-173) в дальнейшем уменьшат комиссии ваших транзакций и предоставят улучшенную защиту от опечаток, однако старые кошельки не поддерживают эти адреса. Если не выбрано, будет создан совместимый со старыми кошелёк.</translation> </message> <message> <source>Generate native segwit (Bech32) address</source> @@ -2031,56 +2245,60 @@ <source>Copy amount</source> <translation>Копировать сумму</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Невозможно разблокировать кошелёк.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Не удалось сгенерировать новый %1 адрес</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-код</translation> + <source>Request payment to ...</source> + <translation>Запросить платёж на ...</translation> </message> <message> - <source>Copy &URI</source> - <translation>Копировать &URI</translation> + <source>Address:</source> + <translation>Адрес:</translation> </message> <message> - <source>Copy &Address</source> - <translation>Копировать &Адрес</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>&Сохранить изображение...</translation> + <source>Amount:</source> + <translation>Количество:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Запросить платёж на %1</translation> + <source>Label:</source> + <translation>Метка:</translation> </message> <message> - <source>Payment information</source> - <translation>Информация о платеже</translation> + <source>Message:</source> + <translation>Сообщение:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Кошелёк:</translation> </message> <message> - <source>Address</source> - <translation>Адрес</translation> + <source>Copy &URI</source> + <translation>Копировать &URI</translation> </message> <message> - <source>Amount</source> - <translation>Количество</translation> + <source>Copy &Address</source> + <translation>Копировать &Адрес</translation> </message> <message> - <source>Label</source> - <translation>Метка</translation> + <source>&Save Image...</source> + <translation>&Сохранить изображение...</translation> </message> <message> - <source>Message</source> - <translation>Сообщение</translation> + <source>Request payment to %1</source> + <translation>Запросить платёж на %1</translation> </message> <message> - <source>Wallet</source> - <translation>Кошелёк</translation> + <source>Payment information</source> + <translation>Информация о платеже</translation> </message> </context> <context> @@ -2190,7 +2408,7 @@ 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>Укажите пользовательскую плату за килобайт (1000 байт) виртуального размера транзакции. -Примечание: Так как комиссия рассчитывается на основе каждого байта, комиссия "100 сатошей за КБ " для транзакции размером 500 байт (половина 1 КБ) в конечном счете, приведет к сбору только 50 сатошей.</translation> +Примечание: Так как комиссия рассчитывается на основе каждого байта, комиссия "100 сатошей за КБ " для транзакции размером 500 байт (половина 1 КБ) в конечном счете приведет к сбору только 50 сатошей.</translation> </message> <message> <source>per kilobyte</source> @@ -2198,7 +2416,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Hide</source> - <translation>Спрятать</translation> + <translation>Скрыть</translation> </message> <message> <source>Recommended:</source> @@ -2301,6 +2519,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%1 (%2 блоков)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Создать Без Подписи</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Создает Частично Подписанную Биткойн Транзакцию (PSBT), чтобы использовать её, например, с оффлайн %1 кошельком, или PSBT-совместимым аппаратным кошельком.</translation> + </message> + <message> <source> from wallet '%1'</source> <translation>с кошелька '%1'</translation> </message> @@ -2313,10 +2539,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>С %1 на %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Вы хотите подготовить черновик транзакции?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Вы действительно хотите выполнить отправку?</translation> </message> <message> + <source>Create Unsigned</source> + <translation>Создать Без Подписи</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Сохранить данные о транзакции</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Частично Подписанная Транзакция (Бинарный файл) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT сохранён</translation> + </message> + <message> <source>or</source> <translation>или</translation> </message> @@ -2325,6 +2571,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Вы можете увеличить комиссию позже (Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Пожалуйста, пересмотрите ваше транзакционное предложение. Это создаст Частично Подписанную Биткойн Транзакцию (PSBT), которую можно сохранить или копировать и использовать для подписи, например, с оффлайн %1 кошельком, или PSBT-совместимым аппаратным кошельком.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Пожалуйста, ознакомьтесь с вашей транзакцией.</translation> </message> @@ -2349,10 +2599,18 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Подтвердить отправку монет</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Подтвердите предложенную транзакцию</translation> + </message> + <message> <source>Send</source> <translation>Отправить</translation> </message> <message> + <source>Watch-only balance:</source> + <translation>Баланс только для просмотра:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Адрес получателя неверный. Пожалуйста, перепроверьте.</translation> </message> @@ -2448,6 +2706,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Удалить эту запись</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>The amount to send in the selected unit</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>С отправляемой суммы будет удержана комиссия. Получателю придёт меньше биткойнов, чем вы вводите в поле количества. Если выбрано несколько получателей, комиссия распределяется поровну.</translation> </message> @@ -2465,7 +2727,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>This is an unauthenticated payment request.</source> - <translation>Это не проверенный запрос на оплату.</translation> + <translation>Это непроверенный запрос на оплату.</translation> </message> <message> <source>This is an authenticated payment request.</source> @@ -2477,7 +2739,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </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>Сообщение прикрепленное к биткойн идентификатору будет сохранено вместе с транзакцией для вашего сведения. Заметьте: Сообщение не будет отправлено через сеть Биткойн.</translation> + <translation>Сообщение, прикрепленное к биткойн-идентификатору, будет сохранено вместе с транзакцией для вашего сведения. Заметьте: Сообщение не будет отправлено через сеть Биткойн.</translation> </message> <message> <source>Pay To:</source> @@ -2567,13 +2829,21 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </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>Введите ниже адрес получателя, сообщение (убедитесь, что переводы строк, пробелы, табы и т.п. в точности скопированы) и подпись, чтобы проверить сообщение. Убедитесь, что не скопировали лишнего в подпись, по сравнению с самим подписываемым сообщением, чтобы не стать жертвой атаки "man-in-the-middle". Заметьте, что эта операция удостоверяет лишь авторство подписавшего, но не может удостоверить отправителя транзакции.</translation> + <translation>Введите ниже адрес получателя, сообщение (убедитесь, что переводы строк, пробелы, табы и т.п. в точности скопированы) и подпись, чтобы проверить сообщение. Убедитесь, что не скопировали лишнего в подпись, сравнив с самим подписываемым сообщением, чтобы не стать жертвой атаки "man-in-the-middle". Заметьте, что эта операция удостоверяет лишь авторство подписавшего, но не может удостоверить отправителя транзакции.</translation> </message> <message> <source>The Bitcoin address the message was signed with</source> <translation>Биткойн-адрес, которым было подписано сообщение</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Подписанное сообщение для проверки</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>The signature given when the message was signed</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Проверить сообщение, чтобы убедиться, что оно было подписано указанным Биткойн-адресом</translation> </message> @@ -2646,7 +2916,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <name>TrafficGraphWidget</name> <message> <source>KB/s</source> - <translation>КБ/сек</translation> + <translation>КБ/с</translation> </message> </context> <context> @@ -2661,7 +2931,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>conflicted with a transaction with %1 confirmations</source> - <translation>конфликт с транзакцией с %1 подтверждений</translation> + <translation>конфликт с транзакцией с %1 подтверждениями</translation> </message> <message> <source>0/unconfirmed, %1</source> @@ -3070,7 +3340,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>ID</source> - <translation>ИН</translation> + <translation>ID</translation> </message> <message> <source>Exporting Failed</source> @@ -3118,12 +3388,28 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Слишком длительное закрытие кошелька может привести к необходимости повторной синхронизации всей цепочки, если включено сокращение.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Закрыть все кошельки</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Вы уверенны, что хотите закрыть все кошельки?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Не был загружен ни один кошелёк.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Кошелёк не был загружен. +Откройте вкладку Файл > Открыть Кошелёк чтобы загрузить кошелёк. +- ИЛИ -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Создать новый кошелёк</translation> </message> </context> <context> @@ -3145,6 +3431,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Желаете увеличить комиссию?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Do you want to draft a transaction with fee increase?</translation> + </message> + <message> <source>Current fee:</source> <translation>Текущая комиссия:</translation> </message> @@ -3161,6 +3451,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Подтвердите оплату</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>Невозможно подготовить черновик транзакции.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT скопирована</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Невозможно подписать транзакцию</translation> </message> @@ -3184,6 +3482,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Экспортировать данные текущей вкладки в файл</translation> </message> <message> + <source>Error</source> + <translation>Ошибка</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Не удалось декодировать PSBT из буфера обмена (неверный base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Загрузить данные о транзакции</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Частично Подписанная Транзакция (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>Файл PSBT должен быть меньше 100 мегабит.</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Не удалось декодировать PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Создать резервную копию кошелька</translation> </message> @@ -3227,10 +3549,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Удаление: последняя синхронизация кошелька вышла за рамки удаленных данных. Вам нужен -reindex (скачать всю цепь блоков в случае удаленного узла)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Ошибка: произошла критическая внутренняя ошибка, для получения деталей см. debug.log</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Очистка хранилища блоков...</translation> </message> @@ -3243,12 +3561,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Разработчики %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Невозможно сгенерировать ключ изменения адреса. Нет ключей во внутреннем пуле ключей и не может генерировать ключи.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation>Невозможно заблокировать каталог данных %s. %s возможно уже работает.</translation> + <translation>Невозможно заблокировать каталог данных %s. %s, возможно, уже работает.</translation> </message> <message> <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> @@ -3259,16 +3573,32 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Ошибка чтения %s! Все ключи прочитаны верно, но данные транзакций или записи адресной книги могут отсутствовать или быть неправильными.</translation> </message> <message> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation>Предоставлен более чем один адрес подключения к скрытым сервисам. %s используется для подключения к автоматически созданному сервису Tor.</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> - <translation>Пожалуйста убедитесь в корректности установки времени и даты на вашем компьютере! Если время установлено неверно, %s не будет работать правильно.</translation> + <translation>Пожалуйста, убедитесь в корректности установки времени и даты на вашем компьютере! Если время установлено неверно, %s не будет работать правильно.</translation> </message> <message> <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> <translation>Пожалуйста, внесите свой вклад, если вы найдете %s полезными. Посетите %s для получения дополнительной информации о программном обеспечении.</translation> </message> <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: Не удалось приготовить утверждение чтобы загрузить sqlite кошелёк версии: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>SQLiteDatabase: Не удалось приготовить утверждение чтобы загрузить id приложения: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <translation>SQLiteDatabase: Кошелёк sqlite имеет неизвестную версию %d. Поддерживается только версия %d</translation> + </message> + <message> <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> - <translation>База данных блоков содержит блок, который появляется из будущего. Это может из-за некорректно установленных даты и времени на вашем компьютере. Остается только перестраивать базу блоков, если вы уверены, что дата и время корректны.</translation> + <translation>База данных блоков содержит блок, который появляется из будущего. Это может произойти из-за некорректно установленных даты и времени на вашем компьютере. Остается только перестраивать базу блоков, если вы уверены, что дата и время корректны.</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> @@ -3276,7 +3606,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </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> @@ -3295,14 +3625,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Внимание: Мы не полностью согласны с подключенными участниками! Вам или другим участникам, возможно, следует обновиться.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d из последних 100 блоков имеют неожиданную версию</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s поврежден, восстановить не удалось</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool должен быть как минимум %d Мб</translation> </message> @@ -3372,13 +3694,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation>Не удалось начать прослушивание на порту. Используйте -listen=0 если вас это устраивает.</translation> + <translation>Не удалось начать прослушивание на порту. Используйте -listen=0, если вас это устраивает.</translation> </message> <message> <source>Failed to rescan the wallet during initialization</source> <translation>Не удалось повторно сканировать кошелёк во время инициализации</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Не удалось проверить базу данных</translation> + </message> + <message> <source>Importing...</source> <translation>Выполняется импорт...</translation> </message> @@ -3407,6 +3733,30 @@ 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>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase: Не удалось произвести проверку базы данных: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: Не удалось загрузить sqlite кошелёк версии: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation>SQLiteDatabase: Не удалось загрузить id приложения: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase: Не удалось приготовить утверждение для проверки базы данных: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase: Ошибка при проверке базы данных: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase: Неожиданный id приложения. Ожидалось %u, а получено %u</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation>Указанная директория с блоками "%s" не существует.</translation> </message> @@ -3427,16 +3777,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Выполняется загрузка P2P-адресов...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Ошибка: мало места на диске!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Загрузка черного списка...</translation> </message> <message> <source>Not enough file descriptors available.</source> - <translation>Недоступно достаточного количества дескрипторов файла.</translation> + <translation>Недоступно достаточное количество дескрипторов файла.</translation> </message> <message> <source>Prune cannot be configured with a negative value.</source> @@ -3495,6 +3841,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Ошибка: Не удалось начать прослушивание входящих подключений (прослушивание вернуло ошибку %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s испорчен. Попробуйте восстановить с помощью инструмента bitcoin-wallet, или используйте резервную копию.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Невозможно обновить не разделенный HD кошелёк без обновления для поддержки предварительно разделенного пула ключей. Пожалуйста, используйте версию 169900 или повторите без указания версии.</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>Неверное значение для -maxtxfee=<amount>: '%s' (минимальная комиссия трансляции %s для предотвращения зависания транзакций)</translation> </message> @@ -3503,10 +3857,34 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Сумма транзакции за вычетом комиссии слишком мала</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Данная ошибка может произойти в том случае, если этот кошелёк не был правильно закрыт и в последний раз был загружен используя версию с более новой версией Berkley DB. Если это так, воспользуйтесь той программой, в которой этот кошелёк открывался в последний раз.</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Это максимальная транзакция, которую вы заплатите (в добавок к обычной плате) для избежания затрат по причине отбора монет.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Для транзакции требуется адрес сдачи, но сгенерировать его не удалось. Пожалуйста, сначала выполните keypoolrefill.</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>Вам необходимо пересобрать базу данных с помощью -reindex, чтобы вернуться к полному режиму. Это приведёт к перезагрузке всей цепи блоков</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Ошибка: произошла критическая внутренняя ошибка, для получения деталей см. debug.log</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Не удалось поставить -peerblockfilters без использования -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Мало места на диске!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Ошибка чтения с базы данных, выполняется закрытие.</translation> </message> @@ -3519,6 +3897,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Ошибка: На диске недостаточно места для %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Пул ключей опустел, пожалуйста сначала выполните keypoolrefill</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Количество комисии (%s) меньше чем настроенное минимальное количество комисии (%s).</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Неверный -onion адрес или имя хоста: '%s'</translation> </message> @@ -3539,6 +3925,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Необходимо указать порт с -whitebind: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Не указан прокси сервер. Используйте -proxy=<ip> или -proxy=<ip:port></translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Режим удаления блоков несовместим с -blockfilterindex.</translation> </message> @@ -3613,10 +4003,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Внимание: Неизвестные правила вступили в силу (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Стираем все транзакции из кошелька...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>Установлено очень большое значение -maxtxfee. Такие большие комиссии могут быть уплачены в отдельной транзакции.</translation> </message> @@ -3629,10 +4015,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Текущая длина строки версии сети (%i) превышает максимальную длину (%i). Уменьшите количество или размер uacomments.</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>Внимание: Файл кошелька поврежден, данные восстановлены! Оригинальный %s сохранен как %s в %s; Если баланс или транзакции некорректны, вы должны восстановить файл из резервной копии.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s задан слишком высоким!</translation> </message> @@ -3646,7 +4028,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation>Кошелёк будет избегать оплат меньших, нежели минимальная комиссия передачи.</translation> + <translation>Кошелёк будет избегать оплат меньше минимальной комиссии передачи.</translation> </message> <message> <source>This is the minimum transaction fee you pay on every transaction.</source> @@ -3677,10 +4059,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Недостаточно средств</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>Невозможно обновить не разделенный HD кошелёк без обновления для поддержки предварительно разделенного пула ключей. Пожалуйста, используйте -upgradewallet=169900 или -upgradeallet без указания версии.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Не удалось оценить комиссию. Резервная комиссия отключена. Подождите несколько блоков или включите -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_si.ts b/src/qt/locale/bitcoin_si.ts index fbcc8ae7bb..c6fb83eda2 100644 --- a/src/qt/locale/bitcoin_si.ts +++ b/src/qt/locale/bitcoin_si.ts @@ -2,10 +2,38 @@ <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>දැනට තෝරාගෙන ඇති ලිපිනය පද්ධති පසුරු පුවරුවට (clipboard) පිටපත් කරන්න</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>Choose the address to send coins to</source> <translation>කාසි යැවිය යුතු ලිපිනය තෝරන්න</translation> </message> @@ -21,7 +49,19 @@ <source>Receiving addresses</source> <translation>ලබන ලිපින</translation> </message> - </context> + <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>Comma separated file (*.csv)</source> + <translation>කොමා වලින් වෙන් කරන ලද ගොනුව (* .csv)</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> @@ -39,13 +79,141 @@ </context> <context> <name>AskPassphraseDialog</name> - </context> + <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>Show passphrase</source> + <translation>මුරපදය පෙන්වන්න</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>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>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>පසුම්බිය සඳහා නව මුරපදය ඇතුළත් කරන්න.<br/>කරුණාකර මුරපදය සඳහා <b>අහඹු අක්ෂර දහයක් හෝ වැඩි ගණනක්</b>, හෝ <b>වචන අටක් හෝ වැඩි ගණනක්</b>භාවිතා කරන්න.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>පසුම්බිය සඳහා පැරණි මුරපදය සහ නව මුරපදය ඇතුළත් කරන්න.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>ඔබේ මුදල් පසුම්බිය සංකේතනය කිරීමෙන් ඔබේ පරිගණකයට අනිෂ්ට මෘදුකාංග (malware) ඇතුලු වීමෙන් කෙරෙන බිට්කොයින් සොරකම් කිරීම් වලින් සම්පූර්ණයෙන්ම වැළැක්වීම කළ නොහැකි බව මතක තබා ගන්න.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>සංකේතනය කළ යුතු පසුම්බිය</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>ඔබේ මුදල් පසුම්බිය සංකේතනය කිරීමට ආසන්නයි.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>ඔබගේ මුදල් පසුම්බිය දැන් සංකේතනය කර ඇත.</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>වැදගත්: ඔබගේ පසුම්බි ගොනුවෙන් ඔබ විසින් සාදන ලද පෙර උපස්ථයන්(backups) අලුතින් ජනනය කරන ලද, සංකේතනය කළ පසුම්බි ගොනුව සමඟ ප්රතිස්ථාපනය(replace) කළ යුතුය. ආරක්ෂක හේතූන් මත, ඔබ නව, සංකේතනය කළ පසුම්බිය භාවිතා කිරීමට පටන් ගත් වහාම සංකේතනය නොකළ පසුම්බි ගොනුවේ පෙර උපස්ථ අක්රීය වනු ඇත.</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>අවවාදයයි: කැප්ස් ලොක් යතුර ක්රියාත්මකයි!</translation> + </message> +</context> <context> <name>BanTableModel</name> + <message> + <source>IP/Netmask</source> + <translation>IP/Netmask</translation> + </message> </context> <context> <name>BitcoinGUI</name> <message> + <source>Browse transaction history</source> + <translation>ගනුදෙනු ඉතිහාසය පිරික්සන්න</translation> + </message> + <message> <source>Warning</source> <translation>අවවාදය</translation> </message> @@ -159,6 +327,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -183,16 +354,8 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>ලිපිනය</translation> - </message> - <message> - <source>Amount</source> - <translation>අගය</translation> - </message> - <message> - <source>Label</source> - <translation>ලේබලය</translation> + <source>Amount:</source> + <translation>අගය:</translation> </message> </context> <context> @@ -277,6 +440,10 @@ <context> <name>TransactionView</name> <message> + <source>Comma separated file (*.csv)</source> + <translation>කොමා වලින් වෙන් කරන ලද ගොනුව (* .csv)</translation> + </message> + <message> <source>Date</source> <translation>දිනය</translation> </message> diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index 8435a49319..6550da8232 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -70,10 +70,6 @@ <translation>Toto sú Vaše Bitcoin adresy pre posielanie platieb. Vždy skontrolujte sumu a prijímaciu adresu pred poslaním mincí.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Toto sú vaše Bitcoin adresy pre prijímanie platieb. Pre vytvorenie nových adries použite tlačidlo 'Vytvoriť novú prijímajúcu adresu' na karte Prijať.</translation> - </message> - <message> <source>&Copy Address</source> <translation>&Kopírovať adresu</translation> </message> @@ -482,6 +478,14 @@ <translation>Aktualizovaný</translation> </message> <message> + <source>Node window</source> + <translation>Uzlové okno</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Otvor konzolu pre ladenie a diagnostiku uzlu</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&Odosielajúce adresy</translation> </message> @@ -490,6 +494,10 @@ <translation>&Prijímajúce adresy</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Otvoriť bitcoin: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Otvoriť peňaženku</translation> </message> @@ -617,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Peňaženka je <b>zašifrovaná</b> a momentálne <b>zamknutá</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Vyskytla sa kritická chyba. Bitcoin nemôže ďalej bezpečne pokračovať a ukončí sa.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -944,7 +948,7 @@ </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>Prvá synchronizácia je veľmi náročná a môžu sa tak vďaka nej začat na Vašom počítači projavovať doteraz skryté hárdwarové problémy. Vždy, keď spustíte %1, bude sťahovanie pokračovať tam, kde skončilo.</translation> + <translation>Prvá synchronizácia je veľmi náročná a môžu sa tak vďaka nej začat na Vašom počítači prejavovať doteraz skryté hardwarové problémy. Vždy, keď spustíte %1, bude sťahovanie pokračovať tam, kde naposledy skončilo.</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> @@ -1050,6 +1054,14 @@ <translation>Skryť</translation> </message> <message> + <source>Esc</source> + <translation>Esc - úniková klávesa</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 sa práve synchronizuje. Sťahujú sa hlavičky a bloky od partnerov. Tie sa budú sa overovať až sa kompletne overí celý reťazec blokov - blockchain.</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Neznámy. Synchronizujú sa hlavičky (%1, %2%)...</translation> </message> @@ -1057,6 +1069,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Otvoriť bitcoin URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1115,10 +1131,6 @@ <translation>Ukazuje, či se zadaná východzia SOCKS5 proxy používá k pripojovaniu k peerom v rámci tohoto typu siete.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Použiť samostatný SOCKS&5 proxy server na dosiahnutie počítačov cez skryté služby Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Skryť ikonu zo systémovej lišty.</translation> </message> @@ -1251,10 +1263,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Pripojiť k Bitcoinovej sieti cez separované SOCKS5 proxy pre skrytú službu Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Okno</translation> </message> @@ -1429,7 +1437,26 @@ <source>Current total balance in watch-only addresses</source> <translation>Aktuálny celkový zostatok pre adries ktoré sa iba sledujú</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialóg</translation> + </message> + <message> + <source>Save...</source> + <translation>Uložiť...</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Celková suma</translation> + </message> + <message> + <source>or</source> + <translation>alebo</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1449,6 +1476,10 @@ <translation>'bitcoin://' je neplatná URI. Použite 'bitcoin:'</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Nemožno spracovať žiadosť o platbu, pretože podpora pre BIP70 nieje podporovaná.</translation> + </message> + <message> <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> <translation>Kvôli mnohým bezpečnostným chybám v BIP70 sa dôrazne odporúča ignorovať inštrukcie na prepínanie peňaženiek od akýchkoľvek obchodníkov.</translation> </message> @@ -1689,10 +1720,6 @@ <translation>Reťazec blokov</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Aktuálny počet blokov</translation> - </message> - <message> <source>Memory Pool</source> <translation>Pamäť Poolu</translation> </message> @@ -1737,10 +1764,6 @@ <translation>Vyberte počítač pre zobrazenie podrobností.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Povolené</translation> - </message> - <message> <source>Direction</source> <translation>Smer</translation> </message> @@ -1762,10 +1785,22 @@ <translation>Synchronizované bloky</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Mapovaný nezávislý - Autonómny Systém používaný na rozšírenie vzájomného výberu partnerov.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapovaný AS</translation> + </message> + <message> <source>User Agent</source> <translation>Aplikácia</translation> </message> <message> + <source>Node window</source> + <translation>Uzlové okno</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>Otvoriť %1 ladiaci výpis z aktuálnej zložky. Pre veľké súbory to môže chvíľu trvať.</translation> </message> @@ -1782,10 +1817,6 @@ <translation>Služby</translation> </message> <message> - <source>Ban Score</source> - <translation>Skóre zákazu</translation> - </message> - <message> <source>Connection Time</source> <translation>Dĺžka spojenia</translation> </message> @@ -1934,14 +1965,6 @@ <translation>Odchádzajúce</translation> </message> <message> - <source>Yes</source> - <translation>Áno</translation> - </message> - <message> - <source>No</source> - <translation>Nie</translation> - </message> - <message> <source>Unknown</source> <translation>neznámy</translation> </message> @@ -1977,8 +2000,16 @@ <translation>Voliteľná požadovaná suma. Nechajte prázdne alebo nulu ak nepožadujete určitú sumu.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Voliteľný popis ktorý sa pridá k tejto novej prijímajúcej adrese (pre jednoduchšiu identifikáciu). Tento popis je taktiež pridaný do výzvy k platbe.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Voliteľná správa ktorá bude pridaná k tejto platobnej výzve a môže byť zobrazená odosielateľovi.</translation> + </message> + <message> <source>&Create new receiving address</source> - <translation>Vytvoriť novú adresu pre prijímanie</translation> + <translation>&Vytvoriť novú príjmaciu adresu</translation> </message> <message> <source>Clear all fields of the form.</source> @@ -2032,12 +2063,28 @@ <source>Copy amount</source> <translation>Kopírovať sumu</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Nepodarilo sa odomknúť peňaženku.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR kód</translation> + <source>Amount:</source> + <translation>Suma:</translation> + </message> + <message> + <source>Label:</source> + <translation>Popis:</translation> + </message> + <message> + <source>Message:</source> + <translation>Správa:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Peňaženka:</translation> </message> <message> <source>Copy &URI</source> @@ -2059,30 +2106,6 @@ <source>Payment information</source> <translation>Informácia o platbe</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adresa</translation> - </message> - <message> - <source>Amount</source> - <translation>Suma</translation> - </message> - <message> - <source>Label</source> - <translation>Popis</translation> - </message> - <message> - <source>Message</source> - <translation>Správa</translation> - </message> - <message> - <source>Wallet</source> - <translation>Peňaženka</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2230,6 +2253,10 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Prach:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Skryť nastavenie poplatkov transakcie</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Ak je v blokoch menej objemu transakcií ako priestoru, ťažiari ako aj vysielacie uzly, môžu uplatniť minimálny poplatok. Platiť iba minimálny poplatok je v poriadku, ale uvedomte si, že to môže mať za následok transakciu, ktorá sa nikdy nepotvrdí, akonáhle je väčší dopyt po bitcoinových transakciách, než dokáže sieť spracovať.</translation> </message> @@ -2298,6 +2325,14 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>%1 (%2 blokov)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Vytvoriť bez podpisu</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Vytvorí čiastočne podpísanú Bitcoin transakciu (Partially Signed Bitcoin Transaction - PSBT) na použitie napríklad s offline %1 peňaženkou alebo v hardvérovej peňaženke kompatibilnej s PSBT.</translation> + </message> + <message> <source> from wallet '%1'</source> <translation> z peňaženky '%1'</translation> </message> @@ -2310,6 +2345,10 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>%1 do %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Chcete naplánovať túto transakciu?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Určite chcete odoslať transakciu?</translation> </message> @@ -2346,6 +2385,18 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Potvrďte odoslanie mincí</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Potvrdiť návrh transakcie</translation> + </message> + <message> + <source>Send</source> + <translation>Odoslať</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Iba sledovaný zostatok:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Adresa príjemcu je neplatná. Prosím, overte ju.</translation> </message> @@ -2441,6 +2492,10 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Odstrániť túto položku</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Suma na odoslanie vo vybranej mene</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>Poplatok sa odpočíta od čiastky, ktorú odosielate. Príjemca dostane menej bitcoinov ako zadáte. Ak je vybraných viacero príjemcov, poplatok je rozdelený rovným dielom.</translation> </message> @@ -2567,6 +2622,14 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Adresa Bitcoin, ktorou bola podpísaná správa</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Podpísaná správa na overenie</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>Poskytnutý podpis pri podpísaní správy</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Overím správy sa uistiť že bola podpísaná označenou Bitcoin adresou</translation> </message> @@ -2599,6 +2662,10 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Odomknutie peňaženky bolo zrušené.</translation> </message> <message> + <source>No error</source> + <translation>Bez chyby</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Súkromný kľúč pre zadanú adresu nieje k dispozícii.</translation> </message> @@ -3107,12 +3174,12 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Zatvorenie peňaženky na príliš dlhú dobu môže mať za následok potrebu znova synchronizovať celý reťazec blokov (blockchain) v prípade, že je aktivované redukovanie blokov.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nie je načítaná peňaženka.</translation> + <source>Create a new wallet</source> + <translation>Vytvoriť novú peňaženku</translation> </message> </context> <context> @@ -3131,7 +3198,11 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato </message> <message> <source>Do you want to increase the fee?</source> - <translation>Chceš poplatok navýšiť?</translation> + <translation>Chcete navýšiť poplatok?</translation> + </message> + <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Chcete naplánovať túto transakciu s navýšením poplatkov.</translation> </message> <message> <source>Current fee:</source> @@ -3150,6 +3221,14 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Potvrď navýšenie poplatku</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>Nemožno naplánovať túto transakciu.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT skopírovaný</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Nemôzeme podpíaať transakciu.</translation> </message> @@ -3173,6 +3252,10 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Exportovať dáta v aktuálnej karte do súboru</translation> </message> <message> + <source>Error</source> + <translation>Chyba</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Zálohovanie peňaženky</translation> </message> @@ -3216,10 +3299,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Redukovanie: posledná synchronizácia peňaženky prebehla pred časmi blokov v redukovaných dátach. Je potrebné vykonať -reindex (v prípade redukovaného režimu stiahne znovu celý reťazec blokov)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Chyba: Vyskytla sa interná chyba, pre viac informácií zobrazte debug.log</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Redukovanie blockstore...</translation> </message> @@ -3232,10 +3311,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Vývojári %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Nie je možné vygenerovať kľúč na zmenu adresy. Nie sú dostupné žiadne kľúče a nie je možné ich ani generovať.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Nemožné uzamknúť zložku %s. %s pravdepodobne už beží.</translation> </message> @@ -3284,14 +3359,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Varovanie: Zjavne sa úplne nezhodujeme s našimi peer-mi! Možno potrebujete prejsť na novšiu verziu alebo ostatné uzly potrebujú vyššiu verziu.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d z posledných 100 blokov má neočakávanú verziu</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s je poškodený, záchrana zlyhala</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool musí byť najmenej %d MB</translation> </message> @@ -3316,6 +3383,14 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Zistená poškodená databáza blokov</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>Nepodarilo sa nájsť asmap súbor %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Nepodarilo sa analyzovať asmap súbor %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Chcete znovu zostaviť databázu blokov?</translation> </message> @@ -3408,10 +3483,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Načítavam P2P adresy…</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Chyba: Príliš málo miesta na disku!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Načítavam banlist...</translation> </message> @@ -3594,10 +3665,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Upozornenie: aktivovaná neznáme nové pravidlá (verzový bit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Zmazať všetky transakcie z peňaženky...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee je nastavené veľmi vysoko! Takto vysoký poplatok môže byť zaplatebý v jednej transakcii.</translation> </message> @@ -3610,10 +3677,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Celková dĺžka verzie sieťového reťazca (%i) prekračuje maximálnu dĺžku (%i). Znížte počet a veľkosť komentárov.</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>Varovanie: Peňaženka poškodená, dáta boli zachránené! Originálna %s ako %s v %s; ak váš zostatok alebo transakcie sú nesprávne, mali by ste obnoviť zálohu.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>Hodnota %s je nastavená veľmi vysoko!</translation> </message> @@ -3658,10 +3721,6 @@ Poznámka: Keďže poplatok je počítaný za bajt, poplatok o hodnote "100 sato <translation>Nedostatok prostriedkov</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> diff --git a/src/qt/locale/bitcoin_sl.ts b/src/qt/locale/bitcoin_sl.ts index 251c040a22..1c84983532 100644 --- a/src/qt/locale/bitcoin_sl.ts +++ b/src/qt/locale/bitcoin_sl.ts @@ -70,8 +70,10 @@ <translation>To so vaši bitcoin-naslovi za pošiljanje. Pred pošiljanjem vedno preverite količino in prejemnikov naslov.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>To so vaši naslovi za prejemanje bitcoinov. Če želite ustvariti nov prejemni naslov, uporabite gumb za ustvarjanje novih naslovov v zavihku "prejemanje".</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>To so vaši bitcoin-naslovi, ki jih uporabljate za prejemanje plačil. Za tvorbo novega naslova uporabite gumb "Ustvari nov prejemni naslov" v zavihku Prejmi. +Podpisovanje je možno le s podedovanimi ("legacy") naslovi.</translation> </message> <message> <source>&Copy Address</source> @@ -267,7 +269,7 @@ </message> <message> <source>Show general overview of wallet</source> - <translation>Oglejte si splošne informacije o vaši denarnici</translation> + <translation>Oglejte si splošne informacije o svoji denarnici</translation> </message> <message> <source>&Transactions</source> @@ -482,6 +484,22 @@ <translation>Ažurno</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>Na&loži DPBT iz datoteke...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Naloži delno podpisano bitcoin-transakcijo</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Naloži DPBT z odložišča...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Naloži delno podpisano bitcoin-transakcijo z odložišča</translation> + </message> + <message> <source>Node window</source> <translation>Okno vozlišča</translation> </message> @@ -518,10 +536,26 @@ <translation>Zapri denarnico</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Zapri vse denarnice...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Zapri vse denarnice</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Pokaži %1 sporočilo za pomoč s seznamom vseh možnosti v ukazni vrstici</translation> </message> <message> + <source>&Mask values</source> + <translation>Za&maskiraj vrednosti</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Zamaskiraj vrednosti v zavihku Pregled</translation> + </message> + <message> <source>default wallet</source> <translation>privzeta denarnica</translation> </message> @@ -630,8 +664,12 @@ <translation>Denarnica je <b>šifrirana</b> in trenutno <b>zaklenjena</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Prišlo je do usodne napake. Bitcoin ne more več varno nadaljevati in se bo zaprl.</translation> + <source>Original message:</source> + <translation>Izvorno sporočilo:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Prišlo je do usodne napake. %1 ne more več varno nadaljevati s tekom in se bo ustavil.</translation> </message> </context> <context> @@ -835,6 +873,14 @@ <translation>Ustvari prazno denarnico</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Uporabi deskriptorje za upravljanje s scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Datoteka z deskriptorji</translation> + </message> + <message> <source>Create</source> <translation>Ustvari</translation> </message> @@ -1139,10 +1185,6 @@ <translation>Prikaže, če je priloženi privzeti proxy SOCKS5 uporabljen za doseganje soležnikov prek te vrste omrežja.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Za dostop do soležnikov preko skritih storitev Tor uporabi drug posredniški strežnik SOCKS&5:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Skrij ikono na sistemskem pladnju.</translation> </message> @@ -1275,10 +1317,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Poveži se v omrežje Bitcoin preko posredniškega strežnika SOCKS5 za skrite storitve Tor.</translation> - </message> - <message> <source>&Window</source> <translation>O&kno</translation> </message> @@ -1319,6 +1357,14 @@ <translation>Omogoči dodatno možnost podrobnega nadzora nad posameznimi kovanci v transakcijah.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Poveži se v omrežje Bitcoin prek ločenega posredniškega strežnika SOCKS5 za storitve onion (Tor).</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Uporabi ločen posredniški strežik SOCKS5 za povezavo s soležniki prek storitev onion (Tor):</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>URL za nakazila &tretjih oseb:</translation> </message> @@ -1435,7 +1481,7 @@ </message> <message> <source>Spendable:</source> - <translation>Na voljo:</translation> + <translation>Na voljo za pošiljanje:</translation> </message> <message> <source>Recent transactions</source> @@ -1453,6 +1499,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Trenutno skupno stanje sredstev na opazovanih naslovih</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>V zavihku Pregled je vklopljen zasebni način. Za prikaz vrednosti odstranite kljukico na mestu Nastavitve > Zamaskiraj vrednosti.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Pogovorno okno</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Podpiši transakcijo</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Oddaj transakcijo v omrežje</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Skopiraj v odložišče</translation> + </message> + <message> + <source>Save...</source> + <translation>Shrani...</translation> + </message> + <message> + <source>Close</source> + <translation>Zapri</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Nalaganje transakcije je spodletelo: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Podpisovanje transakcije je spodletelo: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Ne morem podpisati več vhodov.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>%1 vhodov podpisanih, a potrebnih je več podpisov.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Transakcija je uspešno podpisana in pripravljena na oddajo v omrežje.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Neznana napaka pri obdelavi transakcije.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Transakcija uspešno oddana v omrežje. ID transakcije: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Oddaja transakcije v omrežje je spodletela: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>DPBT kopirana v odložišče.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Shrani podatke transakcije</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Delno podpisana bitcoin-transakcija (binarno) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>DPBT shranjena na disk.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>* Pošlje %1 na %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Ne morem izračunati transakcijske provizije ali skupnega zneska transakcije.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Vsebuje transakcijsko provizijo:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Skupni znesek</translation> + </message> + <message> + <source>or</source> + <translation>ali</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Transakcija ima toliko nepodpisanih vhodov: %1.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>Transakciji manjkajo nekateri podatki o vhodih.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Transakcija potrebuje nadaljnje podpise.</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Ta denarnica pa ne more podpisovati transakcij.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Ta denarnica pa nima pravih ključev.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Transakcija je v celoti podpisana in pripravljena za oddajo v omrežje.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Status transakcije ni znan.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1619,6 +1792,10 @@ <translation>Napaka: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Napaka pri inicializaciji nastavitev: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 se še ni varno zaprl ...</translation> </message> @@ -1717,10 +1894,6 @@ <translation>Veriga blokov</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Trenutno število blokov</translation> - </message> - <message> <source>Memory Pool</source> <translation>Čakalna vrsta transakcij</translation> </message> @@ -1765,10 +1938,6 @@ <translation>Izberite soležnika, o katerem si želite ogledati podrobnejše informacije.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Na seznamu dovoljenih</translation> - </message> - <message> <source>Direction</source> <translation>Smer povezave</translation> </message> @@ -1789,6 +1958,14 @@ <translation>Sinhronizirani bloki</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Mapirani Avtonomski Sistem, uporabljan za diverzificiranje izbire soležnikov.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Mapirani AS</translation> + </message> + <message> <source>User Agent</source> <translation>Ime agenta</translation> </message> @@ -1797,6 +1974,10 @@ <translation>Okno vozlišča</translation> </message> <message> + <source>Current block height</source> + <translation>Višina trenutnega bloka</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>Odpre %1 razhroščevalni dnevnik debug.log, ki se nahaja v trenutni podatkovni mapi. Če je datoteka velika, lahko postopek traja nekaj sekund.</translation> </message> @@ -1809,12 +1990,12 @@ <translation>Povečaj velikost pisave</translation> </message> <message> - <source>Services</source> - <translation>Storitve</translation> + <source>Permissions</source> + <translation>Dovoljenja</translation> </message> <message> - <source>Ban Score</source> - <translation>Kazenske točke</translation> + <source>Services</source> + <translation>Storitve</translation> </message> <message> <source>Connection Time</source> @@ -1965,14 +2146,6 @@ <translation>Odhodna</translation> </message> <message> - <source>Yes</source> - <translation>Da</translation> - </message> - <message> - <source>No</source> - <translation>Ne</translation> - </message> - <message> <source>Unknown</source> <translation>Neznano</translation> </message> @@ -2071,56 +2244,60 @@ <source>Copy amount</source> <translation>Kopiraj znesek</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Denarnice ni bilo mogoče odkleniti.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Ne morem ustvariti novega %1 naslova</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Koda</translation> + <source>Request payment to ...</source> + <translation>Zahtevaj plačilo na ...</translation> </message> <message> - <source>Copy &URI</source> - <translation>Kopiraj &URl</translation> - </message> - <message> - <source>Copy &Address</source> - <translation>Kopiraj &naslov</translation> + <source>Address:</source> + <translation>Naslov:</translation> </message> <message> - <source>&Save Image...</source> - <translation>&Shrani sliko ...</translation> + <source>Amount:</source> + <translation>Znesek:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Zaprosi za plačilo na naslov %1</translation> + <source>Label:</source> + <translation>Oznaka:</translation> </message> <message> - <source>Payment information</source> - <translation>Informacije o plačilu</translation> + <source>Message:</source> + <translation>Sporočilo:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Denarnica:</translation> </message> <message> - <source>Address</source> - <translation>Naslov</translation> + <source>Copy &URI</source> + <translation>Kopiraj &URl</translation> </message> <message> - <source>Amount</source> - <translation>Znesek</translation> + <source>Copy &Address</source> + <translation>Kopiraj &naslov</translation> </message> <message> - <source>Label</source> - <translation>Oznaka</translation> + <source>&Save Image...</source> + <translation>&Shrani sliko ...</translation> </message> <message> - <source>Message</source> - <translation>Sporočilo</translation> + <source>Request payment to %1</source> + <translation>Zaprosi za plačilo na naslov %1</translation> </message> <message> - <source>Wallet</source> - <translation>Denarnica</translation> + <source>Payment information</source> + <translation>Informacije o plačilu</translation> </message> </context> <context> @@ -2350,15 +2527,15 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" </message> <message> <source> from wallet '%1'</source> - <translation>iz denarnice '%1'</translation> + <translation> iz denarnice '%1'</translation> </message> <message> <source>%1 to '%2'</source> - <translation>%1 do '%2'</translation> + <translation>%1 v '%2'</translation> </message> <message> <source>%1 to %2</source> - <translation>%1 do %2</translation> + <translation>%1 v %2</translation> </message> <message> <source>Do you want to draft this transaction?</source> @@ -2366,11 +2543,23 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" </message> <message> <source>Are you sure you want to send?</source> - <translation>Ali ste prepričani, da želite poslati?</translation> + <translation>Ali ste prepričani, da želite poslati sredstva?</translation> + </message> + <message> + <source>Create Unsigned</source> + <translation>Ustvari nepodpisano</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Shrani podatke transakcije</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Delno podpisana bitcoin-transakcija (binarno) (*.psbt)</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Prosimo, preglejte svoj predlog transakcije. Ustvarjena bo delno podpisana bitcoin-transakcija (DPBT, angl. PSBT), ki jo lahko skopirate in potem podpišete n.pr. z nepovezano (offline) %1 denarnico ali pa s hardversko denarnico, ki podpira DPBT.</translation> + <source>PSBT saved</source> + <translation>DPBT shranjena</translation> </message> <message> <source>or</source> @@ -2381,8 +2570,12 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Provizijo lahko zvišate kasneje (signali Replace-By-Fee, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Prosimo, preglejte predlog za transakcijo. Ustvarjena bo delno podpisana bitcoin-transakcija (DPBT), ki jo lahko shranite ali skopirate in potem podpišete n.pr. z nepovezano (offline) %1 denarnico ali pa s hardversko denarnico, ki podpira DPBT.</translation> + </message> + <message> <source>Please, review your transaction.</source> - <translation>Prosimo, preglejte vaše transakcije.</translation> + <translation>Prosimo, preglejte svojo transakcijo.</translation> </message> <message> <source>Transaction fee</source> @@ -2409,18 +2602,10 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Potrdi predlog transakcije</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Kopiraj DPBT v odložišče</translation> - </message> - <message> <source>Send</source> <translation>Pošlji</translation> </message> <message> - <source>PSBT copied</source> - <translation>DPBT skopirana</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Opazovano stanje:</translation> </message> @@ -3202,12 +3387,28 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Predolgo zapiranje denarnice lahko povzroči ponovno sinhronizacijo celotne verige, če je obrezovanje omogočeno.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Zapri vse denarnice</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Ste prepričani, da želite zapreti vse denarnice?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Nobena denarnica ni bila naložena.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Odprta ni nobena denarnica. +Za odpiranje denarnice kliknite Datoteka > Odpri denarnico +- ali pa -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Ustvari novo denarnico</translation> </message> </context> <context> @@ -3280,6 +3481,30 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Izvozi podatke v trenutnem zavihku v datoteko</translation> </message> <message> + <source>Error</source> + <translation>Napaka</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Ne morem dekodirati DPBT z odložišča (neveljaven format base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Naloži podatke transakcije</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Delno podpisana transakcija (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>Velikost DPBT ne sme presegati 100 MiB.</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Ne morem dekodirati DPBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Izdelava varnostne kopije denarnice</translation> </message> @@ -3323,10 +3548,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Obrezovanje: zadnja sinhronizacija denarnice presega obrezane podatke. Izvesti morate -reindex (v primeru obrezanega načina delovanja bo potrebno znova prenesti celotno verigo blokov).</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Napaka: Med izvajanjem je prišlo do nepopravljive napake. Podrobnosti so v datoteki debug.log</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Obrezujem ...</translation> </message> @@ -3339,10 +3560,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>%s razvijalci</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Ne morem ustvariti ključa za naslov za vračilo. Interna zaloga ključev je prazna, novih pa ni mogoče ustvariti.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Ne morem zakleniti podatkovne mape %s. %s je verjetno že zagnan.</translation> </message> @@ -3363,6 +3580,18 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Prosimo, prispevajte, če se vam zdi %s uporaben. Za dodatne informacije o programski opremi obiščite %s.</translation> </message> <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation>Baza SQLite: priprava stavka za poizvedbo verzije sheme SQLite denarnice je spodletela: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>Baza SQLite: priprava stavka za poizvedbo identifikatorja aplikacije je spodletela: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <translation>Baza SQLite: Neznana verzija sheme SQLite denarnice %d. Podprta je le verzija %d.</translation> + </message> + <message> <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> <translation>Baza podatkov blokov vsebuje blok, za katerega se zdi, da je iz prihodnosti. To je lahko posledica napačnega nastavitve datuma in časa vašega računalnika. Znova zgradite bazo podatkov samo, če ste prepričani, da sta datum in čas računalnika pravilna.</translation> </message> @@ -3391,14 +3620,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Opozorilo: Trenutno se s soležniki ne strinjamo v popolnosti! Mogoče bi morali vi ali drugi udeleženci posodobiti odjemalce.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d od zadnjih 100 blokov imajo nepričakovano verzijo</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s poškodovana, obnova neuspešna</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool mora biti vsaj %d MB</translation> </message> @@ -3475,6 +3696,10 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Med inicializacijo denarnice ni bilo mogoče preveriti zgodovine (rescan failed).</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Preverba podatkovne baze je spodletela.</translation> + </message> + <message> <source>Importing...</source> <translation>Uvažam ...</translation> </message> @@ -3503,6 +3728,30 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Neveljavna količina za -fallbackfee=<amount>: '%s'</translation> </message> <message> + <source>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>Baza SQLite: Izvršitev stavka za preverbo baze je spodletela: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>Baza SQLite: pridobitev verzije sheme SQLite denarnice je spodletela: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation>Baza SQLite: pridobitev identifikatorja aplikacije je spodletela: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>Baza SQLite: priprava stavka za preverbo baze je spodletela: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>Baza SQLite: branje napake pri preverjanje baze je spodletelo: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>Baza SQLite: nepričakovan identifikator aplikacije. Pričakovana vrednost je %u, dobljena vrednost je %u.</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation>Vnešena podatkovna mapa za bloke "%s" ne obstaja.</translation> </message> @@ -3523,10 +3772,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Nalagam P2P naslove ...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Napaka: premalo prostora na disku!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Nalaganje liste blokiranih ...</translation> </message> @@ -3591,6 +3836,10 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Napaka: Ni mogoče sprejemati dohodnih povezav (vrnjena napaka: %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s je okvarjena. Lahko jo poskusite popraviti z orodjem bitcoin-wallet ali pa jo obnovite iz varnostne kopije.</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>Neveljaven znesek za -maxtxfee=<amount>: '%s' (mora biti najmanj provizija za %s, da se prepreči zataknjene transakcije)</translation> </message> @@ -3599,10 +3848,30 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Znesek transakcije je premajhen za pošiljanje po odbitku provizije</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Ta napaka se lahko pojavi, če denarnica ni bila pravilno zaprta in je bila nazadnje naložena s programsko opremo z novejšo verzijo Berkely DB. Če je temu tako, prosimo uporabite programsko opremo, s katero je bila ta denarnica nazadnje naložena.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Transakcija potrebuje naslov za vračilo, ki pa ga ni moč ustvariti. Prosimo, najprej pokličite keypoolrefill.</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>Za vrnitev v neobrezan način morate obnoviti bazo z uporabo -reindex. To zahteva ponoven prenos celotne verige blokov.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Prišlo je do usodne notranje napake. Za podrobnosti glejte datoteko debug.log.</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Nastavitev -peerblockfilters ni veljavna brez nastavitve -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Prostora na disku je premalo!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Napaka pri branju podarkovne baze, zapiram.</translation> </message> @@ -3615,6 +3884,10 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Opozorilo: premalo prostora na disku za %s</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Napaka: bazen ključev je prazen, najprej pokličite keypoolrefill</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Neveljaven -onion naslov ali ime gostitelja: '%s'</translation> </message> @@ -3635,6 +3908,10 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Pri opciji -whitebind morate navesti vrata: %s</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Posredniški strežnik (proxy) ni nastavljen. Uporabite -proxy=<ip> ali -proxy=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Obrezovanje ni kompatibilno z -blockfilterindex.</translation> </message> @@ -3709,10 +3986,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Opozorilo: neznana nova pravila aktivirana (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Brišem vse transakcije iz denarnice ...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee je nastavljen zelo visoko!</translation> </message> @@ -3725,10 +3998,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Skupna dolžina niza različice omrežja (%i) presega največjo dolžino (%i). Zmanjšajte število ali velikost ur.</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>Opozorilo: Datoteka denarnice je poškodovana, podatki so shranjeni! Izvirnik %s je bil shranjen kot %s v %s; če je prikazano stanje ali transakcije napačno, ga morate obnoviti iz varnostne kopije.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s je postavljen zelo visoko!</translation> </message> @@ -3773,10 +4042,6 @@ Opomba: Ker se provizija izračuna na bajt, bi provizija "100 satoshijev na kB" <translation>Premalo sredstev</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 morete nadgraditi denarnice, ki ni ločena z HD, brez nadgradnje na podporo pred razdeljenim ključem. Uporabite -upgradewallet=169900 ali -upgradewallet brez določene različice.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Ocena provizije ni uspela. Fallbackfee je onemogočen. Počakajte nekaj blokov ali omogočite -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_sn.ts b/src/qt/locale/bitcoin_sn.ts index a4c24ce077..fa8b9cee20 100644 --- a/src/qt/locale/bitcoin_sn.ts +++ b/src/qt/locale/bitcoin_sn.ts @@ -175,6 +175,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -230,23 +233,7 @@ </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> <context> <name>RecentRequestsTableModel</name> <message> diff --git a/src/qt/locale/bitcoin_sq.ts b/src/qt/locale/bitcoin_sq.ts index da3551e241..4fae82128d 100644 --- a/src/qt/locale/bitcoin_sq.ts +++ b/src/qt/locale/bitcoin_sq.ts @@ -26,10 +26,18 @@ <translation>Fshi adresen e selektuar nga lista</translation> </message> <message> + <source>Enter address or label to search</source> + <translation>Vendos adresën ose etiketën për të kërkuar</translation> + </message> + <message> <source>Export the data in the current tab to a file</source> <translation>Eksporto të dhënat e skedës korrente në një skedar</translation> </message> <message> + <source>&Export</source> + <translation>&Eksporto</translation> + </message> + <message> <source>&Delete</source> <translation>&Fshi</translation> </message> @@ -116,6 +124,10 @@ <translation>Përsërisni fjalëkalimin e ri</translation> </message> <message> + <source>Show passphrase</source> + <translation>Shfaqe fjalëkalimin</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Kripto portofolin</translation> </message> @@ -152,6 +164,26 @@ <translation>Portofoli u enkriptua</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Jepe fjalëkalimin e ri për portofolin. Ju lutemi të përdorni një fjalkalim prej dhjetë ose më shumë shkronjave të rëndomta, ose tetë e më shumë fjalë.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Jepe fjalëkalimin e vjetër dhe fjalkalimin e ri për portofolin.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Portofoli që duhet të enkriptohet</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Portofoli juaj do të enkriptohet</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Portofoli juaj është i enkriptuar.</translation> + </message> + <message> <source>Wallet encryption failed</source> <translation>Enkriptimi i portofolit dështoi</translation> </message> @@ -206,6 +238,10 @@ <translation>Mbyllni aplikacionin</translation> </message> <message> + <source>Show information about Qt</source> + <translation>Shfaq informacion rreth Qt</translation> + </message> + <message> <source>&Options...</source> <translation>&Opsione</translation> </message> @@ -419,6 +455,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -475,30 +514,22 @@ <source>Clear</source> <translation>Pastro</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Nuk mund të ç'kyçet portofoli.</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>&Kopjo adresen</translation> - </message> - <message> - <source>Address</source> - <translation>Adresë</translation> - </message> - <message> - <source>Amount</source> - <translation>Sasia</translation> - </message> - <message> - <source>Label</source> - <translation>Etiketë</translation> + <source>Amount:</source> + <translation>Shuma:</translation> </message> <message> - <source>Wallet</source> - <translation>Portofol</translation> + <source>Copy &Address</source> + <translation>&Kopjo adresen</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -756,9 +787,17 @@ <context> <name>WalletView</name> <message> + <source>&Export</source> + <translation>&Eksporto</translation> + </message> + <message> <source>Export the data in the current tab to a file</source> <translation>Eksporto të dhënat e skedës korrente në një skedar</translation> </message> + <message> + <source>Error</source> + <translation>Problem</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_sr.ts b/src/qt/locale/bitcoin_sr.ts index fecdb44c86..81741a5c60 100644 --- a/src/qt/locale/bitcoin_sr.ts +++ b/src/qt/locale/bitcoin_sr.ts @@ -7,7 +7,7 @@ </message> <message> <source>Create a new address</source> - <translation>Направите нову адресу</translation> + <translation>Направи нову адресу</translation> </message> <message> <source>&New</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>Navedite adresu ili naziv koji bi ste potražili</translation> + <translation>Унеси адресу или назив ознаке за претрагу</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation>Извези податке из одабране картице у фајлj</translation> + <translation>Извези податке из одабране картице у датотеку</translation> </message> <message> <source>&Export</source> @@ -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>&Одабери</translation> </message> <message> <source>Sending addresses</source> @@ -67,7 +67,13 @@ </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. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Ово су твоје Биткоин адресе за приманје уплата. Користи дугме „Направи нову адресу за примање” у картици за примање за креирање нових адреса. +Потписивање је могуђе само за адресе типа 'legacy'.</translation> </message> <message> <source>&Copy Address</source> @@ -102,7 +108,7 @@ <name>AddressTableModel</name> <message> <source>Label</source> - <translation>Етикета</translation> + <translation>Ознака</translation> </message> <message> <source>Address</source> @@ -110,7 +116,7 @@ </message> <message> <source>(no label)</source> - <translation>(без етикете)</translation> + <translation>(без ознаке)</translation> </message> </context> <context> @@ -121,7 +127,7 @@ </message> <message> <source>Enter passphrase</source> - <translation>Унесите лозинку</translation> + <translation>Унеси лозинку</translation> </message> <message> <source>New passphrase</source> @@ -129,7 +135,11 @@ </message> <message> <source>Repeat new passphrase</source> - <translation>Поновите нову лозинку</translation> + <translation>Понови нову лозинку</translation> + </message> + <message> + <source>Show passphrase</source> + <translation>Прикажи лозинку</translation> </message> <message> <source>Encrypt wallet</source> @@ -137,7 +147,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> @@ -145,7 +155,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> @@ -153,7 +163,7 @@ </message> <message> <source>Change passphrase</source> - <translation>Измену лозинку</translation> + <translation>Измени лозинку</translation> </message> <message> <source>Confirm wallet encryption</source> @@ -161,7 +171,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>ИЗГУБИЋЕТЕ СВЕ СВОЈЕ БИТКОИНЕ</b>!</translation> + <translation>Упозорење: Уколико шифрираш новчаник и изгубиш своју лозинку, <b>ИЗГУБИЋЕШ СВЕ СВОЈЕ БИТКОИНЕ</b>!</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> @@ -172,6 +182,30 @@ <translation>Новчаник шифриран</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Унеси нову лозинку за новчаник<br/>Молимо користи лозинку од десет или више насумичних карактера<b>,или<b>осам или више речи</b>.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Унеси стару лозинку и нову лозинку новчаника.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Упамти, шифрирање новчаника не може у потуности заштити твоје биткоине од крађе од стране малвера инфицира твој рачунар.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Новчаник за шифрирање</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Твој новчаник биће шифриран.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Твој новчаник сада је шифриран.</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>ВАЖНО: Свакa претходнa резерва новчаника коју сте имали треба да се замени новим, шифрираним фајлом новчаника. Из сигурносних разлога, свака претходна резерва нешифрираног фајла новчаника постаће сувишна, чим почнете да користите нови, шифрирани новчаник.</translation> </message> @@ -205,7 +239,7 @@ </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation>Упозорање Caps Lock дугме укључено.</translation> + <translation>Упозорање Caps Lock дугме укључено!</translation> </message> </context> <context> @@ -267,7 +301,7 @@ </message> <message> <source>Show information about Qt</source> - <translation>Прегледајте информације о Qt-у</translation> + <translation>Прегледај информације о Qt-у</translation> </message> <message> <source>&Options...</source> @@ -287,15 +321,23 @@ </message> <message> <source>&Change Passphrase...</source> - <translation>Промени &лозинку...</translation> + <translation>& Промени лозинку...</translation> </message> <message> <source>Open &URI...</source> - <translation>Отвори &УРИ...</translation> + <translation>Отвори &URI...</translation> + </message> + <message> + <source>Create Wallet...</source> + <translation>Направи Новчаник...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Направи нови ночаник</translation> </message> <message> <source>Wallet:</source> - <translation>Новчаник</translation> + <translation>Новчаник:</translation> </message> <message> <source>Click to disable network activity.</source> @@ -315,7 +357,7 @@ </message> <message> <source>Reindexing blocks on disk...</source> - <translation>Поново идексирање блокова на диску.</translation> + <translation>Поново идексирање блокова на диску...</translation> </message> <message> <source>Proxy is <b>enabled</b>: %1</source> @@ -323,11 +365,11 @@ </message> <message> <source>Send coins to a Bitcoin address</source> - <translation>Пошаљите новац на Биткоин адресу</translation> + <translation>Пошаљи новац на Биткоин адресу</translation> </message> <message> <source>Backup wallet to another location</source> - <translation>Направите резервну копију новчаника на другој локацији</translation> + <translation>Направи резервну копију новчаника на другој локацији</translation> </message> <message> <source>Change the passphrase used for wallet encryption</source> @@ -427,7 +469,7 @@ </message> <message> <source>Error</source> - <translation>Greška</translation> + <translation>Грешка</translation> </message> <message> <source>Warning</source> @@ -439,7 +481,47 @@ </message> <message> <source>Up to date</source> - <translation>Ажурно</translation> + <translation>Ажурирано</translation> + </message> + <message> + <source>Node window</source> + <translation>Ноде прозор</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Отвори конзолу за ноде дебуг и дијагностику</translation> + </message> + <message> + <source>&Sending addresses</source> + <translation>&Адресе за слање</translation> + </message> + <message> + <source>&Receiving addresses</source> + <translation>&Адресе за примање</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation>Отвори биткоин: URI</translation> + </message> + <message> + <source>Open Wallet</source> + <translation>Отвори новчаник</translation> + </message> + <message> + <source>Open a wallet</source> + <translation>Отвори новчаник</translation> + </message> + <message> + <source>Close Wallet...</source> + <translation>Затвори новчаник...</translation> + </message> + <message> + <source>Close wallet</source> + <translation>Затвори новчаник</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Затвори све новчанике</translation> </message> <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> @@ -450,14 +532,42 @@ <translation>подразумевани новчаник</translation> </message> <message> + <source>No wallets available</source> + <translation>Нема доступних новчаника</translation> + </message> + <message> + <source>Minimize</source> + <translation>Умањи</translation> + </message> + <message> + <source>Zoom</source> + <translation>Увећај</translation> + </message> + <message> + <source>Main Window</source> + <translation>Главни прозор</translation> + </message> + <message> <source>%1 client</source> <translation>%1 клијент</translation> </message> <message> + <source>Connecting to peers...</source> + <translation>Повезивање са клијентима...</translation> + </message> + <message> <source>Catching up...</source> <translation>Ажурирање у току...</translation> </message> <message> + <source>Error: %1</source> + <translation>Грешка: %1</translation> + </message> + <message> + <source>Warning: %1</source> + <translation>Упозорење: %1</translation> + </message> + <message> <source>Date: %1 </source> <translation>Датум: %1 @@ -484,7 +594,7 @@ <message> <source>Label: %1 </source> - <translation>Етикета: %1 + <translation>Ознака: %1 </translation> </message> <message> @@ -495,11 +605,11 @@ </message> <message> <source>Sent transaction</source> - <translation>Послана трансакција</translation> + <translation>Послата трансакција</translation> </message> <message> <source>Incoming transaction</source> - <translation>Придошла трансакција</translation> + <translation>Долазна трансакција</translation> </message> <message> <source>HD key generation is <b>enabled</b></source> @@ -510,18 +620,18 @@ <translation>Генерисање ХД кључа је <b>онеомогућено</b></translation> </message> <message> + <source>Private key <b>disabled</b></source> + <translation>Приватни кључ <b>онемогућен</b></translation> + </message> + <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation>Новчаник јс <b>шифрован</b> и тренутно <b>откључан</b></translation> + <translation>Новчаник јс <b>шифриран</b> и тренутно <b>откључан</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Новчаник јс <b>шифрован</b> и тренутно <b>закључан</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Дошло је до критичне грешке. Биткоин не може безбедно да настави са радом и искључиће се.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -558,8 +668,15 @@ </message> <message> <source>(un)select all</source> - <translation>изаберите / поништите све -</translation> + <translation>(Де)Селектуј све</translation> + </message> + <message> + <source>Tree mode</source> + <translation>Прикажи као стабло</translation> + </message> + <message> + <source>List mode</source> + <translation>Прикажи као листу</translation> </message> <message> <source>Amount</source> @@ -567,7 +684,7 @@ </message> <message> <source>Received with label</source> - <translation>Примљено са етикетом</translation> + <translation>Примљено са ознаком</translation> </message> <message> <source>Received with address</source> @@ -575,7 +692,7 @@ </message> <message> <source>Date</source> - <translation>datum</translation> + <translation>Датум</translation> </message> <message> <source>Confirmations</source> @@ -583,7 +700,7 @@ </message> <message> <source>Confirmed</source> - <translation>Potvrdjen</translation> + <translation>Потврђено</translation> </message> <message> <source>Copy address</source> @@ -591,7 +708,7 @@ </message> <message> <source>Copy label</source> - <translation>Копирај налепницу</translation> + <translation>Копирај ознаку</translation> </message> <message> <source>Copy amount</source> @@ -631,7 +748,7 @@ </message> <message> <source>Copy change</source> - <translation>Копирај промену</translation> + <translation>Копирај кусур</translation> </message> <message> <source>(%1 locked)</source> @@ -646,8 +763,20 @@ <translation>не</translation> </message> <message> + <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> + <translation>Ознака постаје црвена уколико прималац прими износ мањи од износа прашине - сићушног износа.</translation> + </message> + <message> + <source>Can vary +/- %1 satoshi(s) per input.</source> + <translation>Може варирати +/- %1 сатоши(ја) по инпуту.</translation> + </message> + <message> <source>(no label)</source> - <translation>(без налепнице)</translation> + <translation>(без ознаке)</translation> + </message> + <message> + <source>change from %1 (%2)</source> + <translation>Измени од %1 (%2)</translation> </message> <message> <source>(change)</source> @@ -656,10 +785,58 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Креирање новчаника<b>%1... </b>...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Креирање новчаника неуспешно</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Направи упозорење за новчаник</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Направи новчаник</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Име Новчаника</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Шифрирај новчаник. Новчаник ће бити шифриран лозинком коју одаберете.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Шифрирај новчаник</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Онемогући приватни кључ за овај новчаник. Новчаници са онемогућеним приватним кључем неће имати приватни кључ и не могу имати HD семе или увезени приватни кључ. Ова опција идеална је за новчанике који су искључиво за посматрање.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Онемогући Приватне Кључеве</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Направи празан новчаник. Празни новчанци немају приватане кључеве или скрипте. Приватни кључеви могу се увести, или HD семе може бити постављено касније.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Направи Празан Новчаник</translation> + </message> + <message> + <source>Create</source> + <translation>Направи</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -668,11 +845,11 @@ </message> <message> <source>&Label</source> - <translation>&Етикета</translation> + <translation>&Ознака</translation> </message> <message> <source>The label associated with this address list entry</source> - <translation>Етикета повезана са овом ставком из листе адреса</translation> + <translation>Ознака повезана са овом ставком из листе адреса</translation> </message> <message> <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> @@ -699,6 +876,14 @@ <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> @@ -711,7 +896,7 @@ <name>FreespaceChecker</name> <message> <source>A new data directory will be created.</source> - <translation>Нови директоријум података ће бити креиран.</translation> + <translation>Нови директоријум података биће креиран.</translation> </message> <message> <source>name</source> @@ -761,11 +946,15 @@ </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>Када кликнете на ОК, %1 ће почети с преузимањем и процесирањем целокупног ланца блокова %4 (%2GB), почевши од најранијих трансакција у %3 када је %4 покренут.</translation> + <translation>Када кликнете на ОК, %1 ће почети с преузимањем и процесуирањем целокупног ланца блокова %4 (%2GB), почевши од најранијих трансакција у %3 када је %4 покренут.</translation> + </message> + <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Враћање ове опције захтева поновно преузимање целокупног блокчејна - ланца блокова. Брже је преузети цели ланац и касније га скратити. Онемогућава неке напредне опције.</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>Ова иницијална синхронизација је веома захтевна и може изложити ваш рачунар хардверским проблемима који раније нису били примећени. Сваки пут када покренете %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> @@ -784,10 +973,46 @@ <translation>Биткоин</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Обриши блокове након верификације, осим најновије %1 GB (скраћено)</translation> + </message> + <message> + <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> + <translation>Најмање %1 GB подататака биће складиштен у овај директорјиум који ће временом порасти.</translation> + </message> + <message> + <source>Approximately %1 GB of data will be stored in this directory.</source> + <translation>Најмање %1 GB подататака биће складиштен у овај директорјиум.</translation> + </message> + <message> + <source>%1 will download and store a copy of the Bitcoin block chain.</source> + <translation>%1 биће преузеће и складиштити копију Биткоин ланца блокова.</translation> + </message> + <message> + <source>The wallet will also be stored in this directory.</source> + <translation>Новчаник ће бити складиштен у овом директоријуму.</translation> + </message> + <message> + <source>Error: Specified data directory "%1" cannot be created.</source> + <translation>Грешка: Одабрана датотека "%1" не може бити креирана.</translation> + </message> + <message> <source>Error</source> - <translation>Greška</translation> + <translation>Грешка</translation> </message> - </context> + <message numerus="yes"> + <source>%n GB of free space available</source> + <translation><numerusform>Доступно %n GB слободног простора</numerusform><numerusform>Доступно %n GB слободног простора</numerusform><numerusform>Доступно %n GB слободног простора</numerusform></translation> + </message> + <message numerus="yes"> + <source>(of %n GB needed)</source> + <translation><numerusform>(од потребних %n GB)</numerusform><numerusform>(од потребних %n GB)</numerusform><numerusform>(од потребних %n GB)</numerusform></translation> + </message> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB потребно за цео ланац)</numerusform><numerusform>(%n GB потребно за цео ланац)</numerusform><numerusform>(%n GB потребно за цео ланац)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -795,8 +1020,16 @@ <translation>Форма</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>Недавне трансакције можда не буду видљиве, зато салдо твог новчаника можда буде нетачан. Ова информација биђе тачна када новчаник заврши са синхронизацијом биткоин мреже, приказаној испод.</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> + </message> + <message> <source>Number of blocks left</source> - <translation>Остала количина блокова</translation> + <translation>Преостала количина блокова</translation> </message> <message> <source>Unknown...</source> @@ -811,24 +1044,64 @@ <translation>Напредак</translation> </message> <message> + <source>Progress increase per hour</source> + <translation>Пораст напретка по часу</translation> + </message> + <message> <source>calculating...</source> - <translation>Рачунање</translation> + <translation>рачунање...</translation> + </message> + <message> + <source>Estimated time left until synced</source> + <translation>Оквирно време до краја синхронизације</translation> </message> <message> <source>Hide</source> <translation>Сакриј</translation> </message> - </context> + <message> + <source>Esc</source> + <translation>Есц</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 се синхронузује. Преузеће заглавља и блокове од клијената и потврдити их док не стигне на крај ланца блокова.</translation> + </message> + <message> + <source>Unknown. Syncing Headers (%1, %2%)...</source> + <translation>Непознато. Синхронизација заглавља (%1, %2%)...</translation> + </message> +</context> <context> <name>OpenURIDialog</name> - </context> + <message> + <source>Open bitcoin URI</source> + <translation>Отвори биткоин URI</translation> + </message> + <message> + <source>URI:</source> + <translation>URI:</translation> + </message> +</context> <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Отварање новчаника неуспешно</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Упозорење приликом отварања новчаника</translation> + </message> + <message> <source>default wallet</source> <translation>подразумевани новчаник</translation> </message> - </context> + <message> + <source>Opening Wallet <b>%1</b>...</source> + <translation>Отварање новчаника<b>%1</b>...</translation> + </message> +</context> <context> <name>OptionsDialog</name> <message> @@ -836,18 +1109,154 @@ <translation>Поставке</translation> </message> <message> + <source>&Main</source> + <translation>&Главни</translation> + </message> + <message> + <source>Automatically start %1 after logging in to the system.</source> + <translation>Аутоматски почети %1 након пријање на систем.</translation> + </message> + <message> + <source>&Start %1 on system login</source> + <translation>&Покрени %1 приликом пријаве на систем</translation> + </message> + <message> + <source>Size of &database cache</source> + <translation>Величина кеша базе података</translation> + </message> + <message> + <source>Number of script &verification threads</source> + <translation>Број скрипти и CPU за верификацију</translation> + </message> + <message> + <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> + <translation>ИП адреса проксија (нпр. 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 проxy коришћен ради проналажења клијената преко овог типа мреже. </translation> + </message> + <message> + <source>Hide the icon from the system tray.</source> + <translation>Сакриј икону са системске траке.</translation> + </message> + <message> + <source>&Hide tray icon</source> + <translation>&Сакриј икону</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>Минимизирање уместо искључивања апликације када се прозор затвори. Када је ова опција омогућена, апликација ће бити затворена тек након одабира Излаз у менију. </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 треће стране (нпр блок претраживач) који се појављује у менију трансакције. %s у URL замењен је хашом трансакције. Више URL-ова поделено је вертикалом |.</translation> + </message> + <message> + <source>Open the %1 configuration file from the working directory.</source> + <translation>Отвори %1 конфигурациони фајл из директоријума у употреби.</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> + <message> + <source>&Network</source> + <translation>&Мрежа</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>Сакрати &block складиштење на</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>MiB</source> + <translation>MiB</translation> + </message> + <message> + <source>(0 = auto, <0 = leave that many cores free)</source> + <translation>(0 = аутоматски одреди, <0 = остави слободно толико језгара)</translation> + </message> + <message> <source>W&allet</source> - <translation>новчаник</translation> + <translation>Н&овчаник</translation> </message> <message> <source>Expert</source> <translation>Експерт</translation> </message> <message> + <source>Enable coin &control features</source> + <translation>Омогући опцију контроле новчића</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>Уколико онемогућиш трошење непотврђеног кусура, кусур трансакције неће моћи да се користи док транскација нема макар једну потврду. Ово такође утиче како ће се салдо рачунати.</translation> + </message> + <message> + <source>&Spend unconfirmed change</source> + <translation>&Троши непотврђени кусур</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>Аутоматски отвори Биткоин клијент порт на рутеру. Ова опција ради само уколико твој рутер подржава и има омогућен UPnP.</translation> + </message> + <message> + <source>Map port using &UPnP</source> + <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> + <message> + <source>&Connect through SOCKS5 proxy (default proxy):</source> + <translation>&Конектуј се кроз SOCKS5 прокси (уобичајени прокси):</translation> + </message> + <message> + <source>Proxy &IP:</source> + <translation>Прокси &IP:</translation> + </message> + <message> + <source>&Port:</source> + <translation>&Порт:</translation> + </message> + <message> + <source>Port of the proxy (e.g. 9050)</source> + <translation>Прокси порт (нпр. 9050)</translation> + </message> + <message> + <source>Used for reaching peers via:</source> + <translation>Коришћен за приступ другим чворовима преко:</translation> + </message> + <message> <source>IPv4</source> <translation>IPv4</translation> </message> @@ -860,10 +1269,50 @@ <translation>Тор</translation> </message> <message> + <source>Show only a tray icon after minimizing the window.</source> + <translation>Покажи само иконицу у панелу након минимизирања прозора</translation> + </message> + <message> + <source>&Minimize to the tray instead of the taskbar</source> + <translation>&минимизирај у доњу линију, уместо у програмску траку</translation> + </message> + <message> + <source>M&inimize on close</source> + <translation>Минимизирај при затварању</translation> + </message> + <message> + <source>&Display</source> + <translation>&Прикажи</translation> + </message> + <message> + <source>User Interface &language:</source> + <translation>&Језик корисничког интерфејса:</translation> + </message> + <message> + <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> + <translation>Језик корисничког интерфејса може се овде поставити. Ово својство биће на снази након поновног покреања %1.</translation> + </message> + <message> <source>&Unit to show amounts in:</source> <translation>&Јединица за приказивање износа:</translation> </message> <message> + <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> + <translation>Одабери уобичајену подјединицу која се приказује у интерфејсу и када се шаљу новчићи.</translation> + </message> + <message> + <source>Whether to show coin control features or not.</source> + <translation>Да ли да се прикажу опције контроле новчића или не.</translation> + </message> + <message> + <source>&Third party transaction URLs</source> + <translation>&URL-ови трансакција трећих страна</translation> + </message> + <message> + <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> + <translation>Опције постављене у овом диалогу су поништене командном линијом или у конфигурационој датотеци:</translation> + </message> + <message> <source>&OK</source> <translation>&Уреду</translation> </message> @@ -872,10 +1321,50 @@ <translation>&Откажи</translation> </message> <message> + <source>default</source> + <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>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>Конфигурациона датотека се користи да одреди напредне корисничке опције које поништају подешавања у графичком корисничком интерфејсу.</translation> + </message> + <message> <source>Error</source> - <translation>Greška</translation> + <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> @@ -883,117 +1372,775 @@ <translation>Форма</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>Приказана информација може бити застарела. Ваш новчаник се аутоматски синхронизује са Биткоин мрежом након успостављања конекције, али овај процес је још увек у току.</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>Immature:</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>Твој тренутни салдо са гледај-само адресама</translation> + </message> + <message> + <source>Spendable:</source> + <translation>Могуће потрошити:</translation> + </message> + <message> + <source>Recent transactions</source> + <translation>Недавне трансакције</translation> + </message> + <message> + <source>Unconfirmed transactions to watch-only addresses</source> + <translation>Трансакције за гледај-само адресе које нису потврђене</translation> + </message> + <message> + <source>Mined balance in watch-only addresses that has not yet matured</source> + <translation>Салдорударења у адресама које су у моду само гледање, који још увек није доспео</translation> + </message> + <message> + <source>Current total balance in watch-only addresses</source> + <translation>Тренутни укупни салдо у адресама у опцији само-гледај</translation> + </message> </context> <context> - <name>PaymentServer</name> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Дијалог</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Потпиши Трансакцију</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Емитуј Трансакцију</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Копирајте у клипборд.</translation> + </message> + <message> + <source>Save...</source> + <translation>Сачувај...</translation> + </message> + <message> + <source>Close</source> + <translation>Затвори</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Сачувај Податке Трансакције</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Парцијално Потписана Трансакција (Binary) (*.psbt)</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Укупан износ</translation> + </message> + <message> + <source>or</source> + <translation>или</translation> + </message> </context> <context> + <name>PaymentServer</name> + <message> + <source>Payment request error</source> + <translation>Грешка у захтеву за плаћање</translation> + </message> + <message> + <source>Cannot start bitcoin: click-to-pay handler</source> + <translation>Не могу покренути биткоин: "кликни-да-платиш" механизам</translation> + </message> + <message> + <source>URI handling</source> + <translation>URI руковање</translation> + </message> + <message> + <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> + <translation>'bitcoin://' није важећи URI. Уместо тога користити 'bitcoin:'.</translation> + </message> + <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Захтев за плаћање не може се обрадити, јер BIP70 није подржан.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Због великог броја безбедносних пропуста у BIP70, препоручено је да се све инструкције трговаца за промену новчаника игноришу.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Уколико добијате грешку овог типа, потребно је да захтевате од трговца BIP21 компатибилан URI.</translation> + </message> + <message> + <source>Invalid payment address %1</source> + <translation>Неважећа адреса за плаћање %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 се не може рашчланити! Ово може бити проузроковано неважећом Биткоин адресом или погрешно форматираним URI параметрима.</translation> + </message> + <message> + <source>Payment request file handling</source> + <translation>Руковање датотеком захтева за плаћање</translation> + </message> +</context> +<context> <name>PeerTableModel</name> - </context> + <message> + <source>User Agent</source> + <translation>Кориснички агент</translation> + </message> + <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> <source>Amount</source> - <translation>iznos</translation> + <translation>Износ</translation> + </message> + <message> + <source>Enter a Bitcoin address (e.g. %1)</source> + <translation>Унеси Биткоин адресу, (нпр %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>Nijedan</translation> + </message> + <message> + <source>N/A</source> + <translation>Није применљиво</translation> + </message> + <message> + <source>%1 ms</source> + <translation>%1 ms</translation> + </message> + <message numerus="yes"> + <source>%n second(s)</source> + <translation><numerusform>%n секунда</numerusform><numerusform>%n секунди</numerusform><numerusform>%n секунди</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n minute(s)</source> + <translation><numerusform>%n минут</numerusform><numerusform>%n минута</numerusform><numerusform>%n минута</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n hour(s)</source> + <translation><numerusform>%n час</numerusform><numerusform>%n часа</numerusform><numerusform>%n часова</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n day(s)</source> + <translation><numerusform>%n минут</numerusform><numerusform>%n минута</numerusform><numerusform>%n минута</numerusform></translation> + </message> + <message numerus="yes"> + <source>%n week(s)</source> + <translation><numerusform>%n недеља</numerusform><numerusform>%n недеље</numerusform><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><numerusform>%n године</numerusform><numerusform>%n година</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>Error: Specified data directory "%1" does not exist.</source> + <translation>Грешка: Одабрани директорјиум датотеке "%1" не постоји.</translation> + </message> + <message> + <source>Error: %1</source> + <translation>Грешка: %1</translation> + </message> + <message> + <source>%1 didn't yet exit safely...</source> + <translation>%1 није изашао безбедно...</translation> </message> <message> <source>unknown</source> - <translation>nepoznato</translation> + <translation>непознато</translation> </message> </context> <context> <name>QRImageWidget</name> - </context> + <message> + <source>&Save Image...</source> + <translation>&Сачувај Слику...</translation> + </message> + <message> + <source>&Copy Image</source> + <translation>&Копирај Слику</translation> + </message> + <message> + <source>Resulting URI too long, try to reduce the text for label / message.</source> + <translation>Дати резултат URI предуг, покушај да сманиш текст за ознаку / поруку.</translation> + </message> + <message> + <source>Error encoding URI into QR Code.</source> + <translation>Грешка током енкодирања URI у QR Код.</translation> + </message> + <message> + <source>QR code support not available.</source> + <translation>QR код подршка није доступна.</translation> + </message> + <message> + <source>Save QR Code</source> + <translation>Упамти QR Код</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>Верзија клијента</translation> + </message> + <message> + <source>&Information</source> + <translation>&Информације</translation> + </message> + <message> + <source>General</source> + <translation>Опште</translation> + </message> + <message> + <source>Using BerkeleyDB version</source> + <translation>Коришћење BerkeleyDB верзије.</translation> + </message> + <message> + <source>Datadir</source> + <translation>Datadir</translation> + </message> + <message> + <source>To specify a non-default location of the data directory use the '%1' option.</source> + <translation>Да би сте одредили локацију која није унапред задата за директоријум података користите '%1' опцију.</translation> + </message> + <message> + <source>Blocksdir</source> + <translation>Blocksdir</translation> + </message> + <message> + <source>To specify a non-default location of the blocks directory use the '%1' option.</source> + <translation>Да би сте одредили локацију која није унапред задата за директоријум блокова користите '%1' опцију.</translation> + </message> + <message> + <source>Startup time</source> + <translation>Време подизања система</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> + <message> + <source>Block chain</source> + <translation>Блокчејн</translation> + </message> + <message> + <source>Memory Pool</source> + <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>Direction</source> + <translation>Правац</translation> + </message> + <message> + <source>Version</source> + <translation>Верзија</translation> + </message> + <message> + <source>Starting Block</source> + <translation>Почетни блок</translation> + </message> + <message> + <source>Synced Headers</source> + <translation>Синхронизована заглавља</translation> + </message> + <message> + <source>Synced Blocks</source> + <translation>Синхронизовани блокови</translation> + </message> + <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Мапирани аутономни систем који се користи за диверсификацију селекције колега чворова.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Мапирани АС</translation> + </message> + <message> + <source>User Agent</source> + <translation>Кориснички агент</translation> + </message> + <message> + <source>Node window</source> + <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> + <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>The duration of a currently outstanding ping.</source> + <translation>Трајање тренутно неразрешеног пинга.</translation> + </message> + <message> + <source>Ping Wait</source> + <translation>Чекање на пинг</translation> + </message> + <message> + <source>Min Ping</source> + <translation>Мин Пинг</translation> + </message> + <message> + <source>Time Offset</source> + <translation>Помак времена</translation> + </message> + <message> <source>Last block time</source> <translation>Време последњег блока</translation> </message> <message> - <source>Yes</source> - <translation>Da</translation> + <source>&Open</source> + <translation>&Отвори</translation> </message> <message> - <source>No</source> - <translation>Ne</translation> + <source>&Console</source> + <translation>&Конзола</translation> </message> - </context> + <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>Debug log file</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>Welcome to the %1 RPC console.</source> + <translation>Добродошли на %1 RPC конзоле.</translation> + </message> + <message> + <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> + <translation>Користи стрелице горе и доле за навигацију историје, и %1 зa чишћење екрана.</translation> + </message> + <message> + <source>Type %1 for an overview of available commands.</source> + <translation>Укуцај %1 за преглед доступних команди.</translation> + </message> + <message> + <source>For more information on using this console type %1.</source> + <translation>За више информација о коришћењу конзиле укуцај %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>УПОЗОРЕЊЕ: Преваранти активно говоре корисницима да овде укуцају команде, том приликом краду садржај новчаника. Немојте користити конзолу без претходног разумевања последица коришћења команди.</translation> + </message> + <message> + <source>Network activity disabled</source> + <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>(node id: %1)</translation> + </message> + <message> + <source>via %1</source> + <translation>преко %1</translation> + </message> + <message> + <source>never</source> + <translation>никад</translation> + </message> + <message> + <source>Inbound</source> + <translation>Долазеће</translation> + </message> + <message> + <source>Outbound</source> + <translation>Одлазеће</translation> + </message> + <message> + <source>Unknown</source> + <translation>Непознато</translation> + </message> +</context> <context> <name>ReceiveCoinsDialog</name> <message> <source>&Amount:</source> - <translation>Iznos:</translation> + <translation>&Износ:</translation> </message> <message> <source>&Label:</source> - <translation>&Етикета</translation> + <translation>&Ознака</translation> </message> <message> <source>&Message:</source> <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>Опциона порука коју можеш прикачити уз захтев за плаћање, која ће бити приказана када захтев буде отворен. Напомена: Порука неће бити послата са уплатом на Биткоин мрежи.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address.</source> + <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>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> + <translation>Опциони износ за захтев. Остави празно или нула уколико не желиш прецизирати износ.</translation> + </message> + <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Опционална ознака за поистовећивање са новом адресом примаоца (користите је за идентификацију рачуна). Она је такође придодата захтеву за плаћање.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Опциона порука која је придодата захтеву за плаћање и може бити приказана пошиљаоцу.</translation> + </message> + <message> + <source>&Create new receiving address</source> + <translation>&Направи нову адресу за примање</translation> + </message> + <message> + <source>Clear all fields of the form.</source> + <translation>Очисти сва пола форме.</translation> + </message> + <message> + <source>Clear</source> + <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> + <message> + <source>Show the selected request (does the same as double clicking an entry)</source> + <translation>Прикажи селектовани захтев (има исту сврху као и дупли клик на одговарајући унос)</translation> + </message> + <message> <source>Show</source> - <translation>Prikaži</translation> + <translation>Прикажи</translation> + </message> + <message> + <source>Remove the selected entries from the list</source> + <translation>Уклони одабрани унос из листе</translation> + </message> + <message> + <source>Remove</source> + <translation>Уклони</translation> + </message> + <message> + <source>Copy URI</source> + <translation>Копирај URI</translation> </message> <message> <source>Copy label</source> - <translation>Копирај налепницу -</translation> + <translation>Копирај ознаку</translation> + </message> + <message> + <source>Copy message</source> + <translation>Копирај поруку</translation> </message> <message> <source>Copy amount</source> - <translation>к</translation> + <translation>Копирај износ</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Новчаник није могуће откључати.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>Kopirajte adresu</translation> + <source>Address:</source> + <translation>Адреса:</translation> </message> <message> - <source>Address</source> - <translation>Adresa</translation> + <source>Amount:</source> + <translation>Износ:</translation> </message> <message> - <source>Amount</source> - <translation>Износ</translation> + <source>Label:</source> + <translation>Етикета</translation> </message> <message> - <source>Label</source> - <translation>Налепница</translation> + <source>Message:</source> + <translation>Порука:</translation> </message> <message> - <source>Message</source> - <translation>Poruka</translation> + <source>Wallet:</source> + <translation>Новчаник:</translation> </message> <message> - <source>Wallet</source> - <translation>Новчаник</translation> + <source>Copy &URI</source> + <translation>Копирај &URI</translation> + </message> + <message> + <source>Copy &Address</source> + <translation>Копирај &Адресу</translation> + </message> + <message> + <source>&Save Image...</source> + <translation>&Сачувај Слику...</translation> + </message> + <message> + <source>Request payment to %1</source> + <translation>Захтевај уплату ка %1</translation> + </message> + <message> + <source>Payment information</source> + <translation>Информације о плаћању</translation> </message> </context> <context> <name>RecentRequestsTableModel</name> <message> <source>Date</source> - <translation>datum</translation> + <translation>Датум</translation> </message> <message> <source>Label</source> - <translation>Налепница</translation> + <translation>Ознака</translation> </message> <message> <source>Message</source> @@ -1001,14 +2148,42 @@ </message> <message> <source>(no label)</source> - <translation>(без налепнице)</translation> + <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> <source>Send Coins</source> - <translation>Слање новца</translation> + <translation>Пошаљи новчиће</translation> + </message> + <message> + <source>Coin Control Features</source> + <translation>Опција контроле новчића</translation> + </message> + <message> + <source>Inputs...</source> + <translation>Инпути...</translation> + </message> + <message> + <source>automatically selected</source> + <translation>аутоматски одабрано</translation> + </message> + <message> + <source>Insufficient funds!</source> + <translation>Недовољно средстава!</translation> </message> <message> <source>Quantity:</source> @@ -1020,7 +2195,7 @@ </message> <message> <source>Amount:</source> - <translation>Iznos:</translation> + <translation>Износ:</translation> </message> <message> <source>Fee:</source> @@ -1032,17 +2207,109 @@ </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> + </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>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>Коришћење безбедносне накнаде може резултовати у времену потребно за потврду трансакције од неколико сати или дана (или никад). Размислите о ручном одабиру провизије или сачекајте док нисте потврдили комплетан ланац.</translation> + </message> + <message> + <source>Warning: Fee estimation is currently not possible.</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>Одредити прилагођену провизију по kB (1,000 битова) виртуелне величине трансакције. + +Напомена: С обзиром да се провизија рачуна на основу броја бајтова, провизија за "100 сатошија по kB" за величину трансакције од 500 бајтова (пола од 1 kB) ће аутоматски износити само 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>Hide transaction fee settings</source> + <translation>Сакријте износ накнаде за трансакцију</translation> + </message> + <message> + <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> + <translation>Када је мањи обим трансакција од простора у блоку, рудари, као и повезани нодови могу применити минималну провизију. Плаћање само минималне накнаде - провизије је добро, али треба бити свестан да ово може резултовати трансакцијом која неће никада бити потврђена, у случају када је број захтева за биткоин трансакцијама већи од могућности мреже да обради.</translation> + </message> + <message> + <source>A too low fee might result in a never confirming transaction (read the tooltip)</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>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>Са Замени-за-Провизију (BIP-125) се може повећати висина провизије за трансакцију након што је послата. Без овога, виша провизија може бити препоручена да се смањи ризик од кашњења трансакције. </translation> + </message> + <message> + <source>Clear &All</source> + <translation>Очисти &Све</translation> + </message> + <message> + <source>Balance:</source> + <translation>Салдо:</translation> + </message> + <message> <source>Confirm the send action</source> <translation>Потврди акцију слања</translation> </message> @@ -1056,7 +2323,7 @@ </message> <message> <source>Copy amount</source> - <translation>к</translation> + <translation>Копирај износ</translation> </message> <message> <source>Copy fee</source> @@ -1079,141 +2346,649 @@ <translation>Копирај промену</translation> </message> <message> + <source>%1 (%2 blocks)</source> + <translation>%1 (%2 блокови)</translation> + </message> + <message> + <source>Cr&eate Unsigned</source> + <translation>Креирај непотписано</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Креира делимично потписану Биткоин трансакцију (PSBT) за коришћење са нпр. офлајн %1 новчаником, или PSBT компатибилним хардверским новчаником. </translation> + </message> + <message> + <source> from wallet '%1'</source> + <translation>из новчаника '%1'</translation> + </message> + <message> + <source>%1 to '%2'</source> + <translation>%1 до '%2'</translation> + </message> + <message> + <source>%1 to %2</source> + <translation>%1 до %2</translation> + </message> + <message> + <source>Do you want to draft this transaction?</source> + <translation>Да ли желите да саставите ову трансакцију?</translation> + </message> + <message> + <source>Are you sure you want to send?</source> + <translation>Да ли сте сигурни да желите да пошаљете?</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Сачувај Податке Трансакције</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Делимично Потписана Трансакција (Binary) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT сачуван</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>Можете повећати провизију касније (сигнали Замени-са-Провизијом, BIP-125).</translation> + </message> + <message> + <source>Please, review your transaction.</source> + <translation>Молим, размотрите вашу трансакцију.</translation> + </message> + <message> + <source>Transaction fee</source> + <translation>Провизија за трансакцију</translation> + </message> + <message> + <source>Not signalling Replace-By-Fee, BIP-125.</source> + <translation>Не сигнализира Замени-са-Провизијом, BIP-125.</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Укупан износ</translation> + </message> + <message> + <source>To review recipient list click "Show Details..."</source> + <translation>Да би сте размотрили листу примаоца кликните на "Прикажи детаље..."</translation> + </message> + <message> + <source>Confirm send coins</source> + <translation>Потврдите слање новчића</translation> + </message> + <message> + <source>Confirm transaction proposal</source> + <translation>Потврдите предлог трансакције</translation> + </message> + <message> + <source>Send</source> + <translation>Пошаљи</translation> + </message> + <message> + <source>Watch-only balance:</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>The total exceeds your balance when the %1 transaction fee is included.</source> + <translation>Укупни износ премашује ваш салдо, када се %1 провизија за трансакцију укључи у износ.</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>A fee higher than %1 is considered an absurdly high fee.</source> + <translation>Провизија већа од %1 се сматра апсурдно високом провизијом.</translation> + </message> + <message> + <source>Payment request expired.</source> + <translation>Захтев за плаћање је истекао.</translation> + </message> + <message numerus="yes"> + <source>Estimated to begin confirmation within %n block(s).</source> + <translation><numerusform>Процењује се да ће започети потврду унутар %n блока.</numerusform><numerusform>Процењује се да ће започети потврду унутар %n блока.</numerusform><numerusform>Процењује се да ће започети потврду унутар %n блокова.</numerusform></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> + <translation>(без ознаке)</translation> </message> </context> <context> <name>SendCoinsEntry</name> <message> <source>A&mount:</source> - <translation>Iznos:</translation> + <translation>&Износ:</translation> + </message> + <message> + <source>Pay &To:</source> + <translation>Плати &За:</translation> </message> <message> <source>&Label:</source> - <translation>&Етикета</translation> + <translation>&Ознака</translation> + </message> + <message> + <source>Choose previously used address</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+</translation> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Налепите адресу из базе за копирање</translation> </message> <message> <source>Alt+P</source> <translation>Alt+П</translation> </message> <message> + <source>Remove this entry</source> + <translation>Уклоните овај унос</translation> + </message> + <message> + <source>The amount to send in the selected unit</source> + <translation>Износ који ће бити послат у одабрану јединицу</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>Провизија ће бити одузета од износа који је послат. Примаоц ће добити мање биткоина него што је унесено у поље за износ. Уколико је одабрано више примаоца, провизија се дели равномерно.</translation> + </message> + <message> + <source>S&ubtract fee from amount</source> + <translation>&Одузми провизију од износа</translation> + </message> + <message> + <source>Use available balance</source> + <translation>Користи расположиви салдо</translation> + </message> + <message> <source>Message:</source> - <translation>Poruka:</translation> + <translation>Порука:</translation> </message> - </context> + <message> + <source>This is an unauthenticated payment request.</source> + <translation>Ово је неовлашћени захтев за плаћање.</translation> + </message> + <message> + <source>This is an authenticated payment request.</source> + <translation>Ово је овлашћени захтев за плаћање.</translation> + </message> + <message> + <source>Enter a label for this address to add it to the list of used addresses</source> + <translation>Унесите ознаку за ову адресу да бисте је додали на листу коришћених адреса</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>Порука која је приложена биткоину: URI која ће бити сачувана уз трансакцију ради референце. Напомена: Ова порука се шаље преко Биткоин мреже.</translation> + </message> + <message> + <source>Pay To:</source> + <translation>Плати ка:</translation> + </message> + <message> + <source>Memo:</source> + <translation>Мемо:</translation> + </message> +</context> <context> <name>ShutdownWindow</name> - </context> + <message> + <source>%1 is shutting down...</source> + <translation>%1 се искључује</translation> + </message> + <message> + <source>Do not shut down the computer until this window disappears.</source> + <translation>Немојте искључити рачунар док овај прозор не нестане.</translation> + </message> +</context> <context> <name>SignVerifyMessageDialog</name> <message> + <source>Signatures - Sign / Verify a Message</source> + <translation>Потписи - Потпиши / Потврди поруку</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>Можете потписати поруку/споразум са вашом адресом да би сте доказали да можете примити биткоин послат ка њима. Будите опрезни да не потписујете ништа нејасно или случајно, јер се може десити напад крађе идентитета, да потпишете ваш идентитет нападачу. Потпишите само потпуно детаљне изјаве са којима се слажете.</translation> + </message> + <message> + <source>The Bitcoin address to sign the message with</source> + <translation>Биткоин адреса са којом ћете потписати поруку</translation> + </message> + <message> + <source>Choose previously used address</source> + <translation>Промени претходно коришћену адресу</translation> + </message> + <message> <source>Alt+A</source> - <translation>Alt+</translation> + <translation>Alt+A</translation> + </message> + <message> + <source>Paste address from clipboard</source> + <translation>Налепите адресу из базе за копирање</translation> </message> <message> <source>Alt+P</source> - <translation>Alt+П</translation> + <translation>Alt+P</translation> </message> - </context> + <message> + <source>Enter the message you want to sign here</source> + <translation>Унесите поруку коју желите да потпишете овде</translation> + </message> + <message> + <source>Signature</source> + <translation>Потпис</translation> + </message> + <message> + <source>Copy the current signature to the system clipboard</source> + <translation>Копирајте тренутни потпис у системску базу за копирање</translation> + </message> + <message> + <source>Sign the message to prove you own this Bitcoin address</source> + <translation>Потпишите поруку да докажете да сте власник ове Биткоин адресе</translation> + </message> + <message> + <source>Sign &Message</source> + <translation>Потпис &Порука</translation> + </message> + <message> + <source>Reset all sign message fields</source> + <translation>Поништите сва поља за потписивање поруке</translation> + </message> + <message> + <source>Clear &All</source> + <translation>Очисти &Све</translation> + </message> + <message> + <source>&Verify Message</source> + <translation>&Потврди поруку</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>Унесите адресу примаоца, поруку (осигурајте да тачно копирате прекиде линија, размаке, картице итд) и потпишите испод да потврдите поруку. Будите опрезни да не убаците више у потпис од онога што је у потписаној поруци, да би сте избегли напад посредника. Имајте на уму да потпис само доказује да потписник прима са потписаном адресом, а не може да докаже слање било које трансакције!</translation> + </message> + <message> + <source>The Bitcoin address the message was signed with</source> + <translation>Биткоин адреса са којом је потписана порука</translation> + </message> + <message> + <source>The signed message to verify</source> + <translation>Потписана порука за потврду</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>Потпис који је дат приликом потписивања поруке</translation> + </message> + <message> + <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> + <translation>Потврдите поруку да осигурате да је потписана са одговарајућом Биткоин адресом</translation> + </message> + <message> + <source>Verify &Message</source> + <translation>Потврди &Поруку</translation> + </message> + <message> + <source>Reset all verify message fields</source> + <translation>Поништите сва поља за потврду поруке</translation> + </message> + <message> + <source>Click "Sign Message" to generate signature</source> + <translation>Притисни "Потпиши поруку" за израду потписа</translation> + </message> + <message> + <source>The entered address is invalid.</source> + <translation>Унесена адреса није важећа.</translation> + </message> + <message> + <source>Please check the address and try again.</source> + <translation>Молим проверите адресу и покушајте поново.</translation> + </message> + <message> + <source>The entered address does not refer to a key.</source> + <translation>Унесена адреса се не односи на кључ.</translation> + </message> + <message> + <source>Wallet unlock was cancelled.</source> + <translation>Откључавање новчаника је отказано.</translation> + </message> + <message> + <source>No error</source> + <translation>Нема грешке</translation> + </message> + <message> + <source>Private key for the entered address is not available.</source> + <translation>Приватни кључ за унесену адресу није доступан.</translation> + </message> + <message> + <source>Message signing failed.</source> + <translation>Потписивање поруке није успело.</translation> + </message> + <message> + <source>Message signed.</source> + <translation>Порука је потписана.</translation> + </message> + <message> + <source>The signature could not be decoded.</source> + <translation>Потпис не може бити декодиран.</translation> + </message> + <message> + <source>Please check the signature and try again.</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>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>Отворено за још %n блок.</numerusform><numerusform>Отворено за још %n блока</numerusform><numerusform>Отворено за још %n блокова</numerusform></translation> + </message> <message> <source>Open until %1</source> <translation>Otvoreno do %1</translation> </message> <message> + <source>0/unconfirmed, %1</source> + <translation>0/непотврђено, %1</translation> + </message> + <message> + <source>in memory pool</source> + <translation>у удруженој меморији</translation> + </message> + <message> + <source>not in memory pool</source> + <translation>није у удруженој меморији</translation> + </message> + <message> + <source>abandoned</source> + <translation>напуштено</translation> + </message> + <message> <source>%1/unconfirmed</source> - <translation>%1/nepotvrdjeno</translation> + <translation>%1/непотврђено</translation> </message> <message> <source>%1 confirmations</source> - <translation>%1 potvrde</translation> + <translation>%1 порврде</translation> + </message> + <message> + <source>Status</source> + <translation>Статус</translation> </message> <message> <source>Date</source> - <translation>datum</translation> + <translation>Датум</translation> + </message> + <message> + <source>Source</source> + <translation>Извор</translation> + </message> + <message> + <source>Generated</source> + <translation>Генерисано</translation> + </message> + <message> + <source>From</source> + <translation>Од</translation> </message> <message> <source>unknown</source> - <translation>nepoznato</translation> + <translation>непознато</translation> + </message> + <message> + <source>To</source> + <translation>За</translation> + </message> + <message> + <source>own address</source> + <translation>сопствена адреса</translation> + </message> + <message> + <source>watch-only</source> + <translation>гледај-само</translation> </message> <message> <source>label</source> - <translation>етикета</translation> + <translation>ознака</translation> + </message> + <message> + <source>Credit</source> + <translation>Заслуге</translation> + </message> + <message numerus="yes"> + <source>matures in %n more block(s)</source> + <translation><numerusform>сазрева за %n блок</numerusform><numerusform>сазрева за %n блока</numerusform><numerusform>сазрева за %n блокова</numerusform></translation> + </message> + <message> + <source>not accepted</source> + <translation>није прихваћено</translation> + </message> + <message> + <source>Debit</source> + <translation>Задужење</translation> + </message> + <message> + <source>Total debit</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>Poruka</translation> + <translation>Порука</translation> + </message> + <message> + <source>Comment</source> + <translation>Коментар</translation> + </message> + <message> + <source>Transaction ID</source> + <translation>ID Трансакције</translation> + </message> + <message> + <source>Transaction total size</source> + <translation>Укупна величина трансакције</translation> + </message> + <message> + <source>Transaction virtual size</source> + <translation>Виртуелна величина трансакције</translation> + </message> + <message> + <source>Output index</source> + <translation>Излазни индекс</translation> + </message> + <message> + <source> (Certificate was not verified)</source> + <translation>(Сертификат још није проверен)</translation> + </message> + <message> + <source>Merchant</source> + <translation>Трговац</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>Генерисани новчићи морају доспети %1 блокова пре него што могу бити потрошени. Када генеришете овај блок, он се емитује у мрежу, да би био придодат на ланац блокова. Укупно не успе да се придода на ланац, његово стање се мења у "није прихваћен" и неће га бити могуће потрошити. Ово се може повремено десити уколико други чвор генерише блок у периоду од неколико секунди од вашег.</translation> + </message> + <message> + <source>Debug information</source> + <translation>Информације о оклањању грешака</translation> </message> <message> <source>Transaction</source> - <translation>transakcije</translation> + <translation>Трансакције</translation> + </message> + <message> + <source>Inputs</source> + <translation>Инпути</translation> </message> <message> <source>Amount</source> <translation>Износ</translation> </message> - </context> + <message> + <source>true</source> + <translation>тачно</translation> + </message> + <message> + <source>false</source> + <translation>нетачно</translation> + </message> +</context> <context> <name>TransactionDescDialog</name> <message> <source>This pane shows a detailed description of the transaction</source> - <translation>Ovaj odeljak pokazuje detaljan opis transakcije</translation> + <translation>Овај одељак приказује детањан приказ трансакције</translation> </message> - </context> + <message> + <source>Details for %1</source> + <translation>Детаљи за %1</translation> + </message> +</context> <context> <name>TransactionTableModel</name> <message> <source>Date</source> - <translation>datum</translation> + <translation>Датум</translation> </message> <message> <source>Type</source> - <translation>tip</translation> + <translation>Тип</translation> </message> <message> <source>Label</source> - <translation>Налепница</translation> + <translation>Ознака</translation> + </message> + <message numerus="yes"> + <source>Open for %n more block(s)</source> + <translation><numerusform>Отворено за још %n блок </numerusform><numerusform>Отворено за још %n блока</numerusform><numerusform> Отворено за још %n блокова</numerusform></translation> </message> <message> <source>Open until %1</source> - <translation>Otvoreno do %1</translation> + <translation>Отворено до %1</translation> + </message> + <message> + <source>Unconfirmed</source> + <translation>Непотврђено</translation> + </message> + <message> + <source>Abandoned</source> + <translation>Напуштено</translation> + </message> + <message> + <source>Confirming (%1 of %2 recommended confirmations)</source> + <translation>Потврђивање у току (%1 од %2 препоручене потврде)</translation> </message> <message> <source>Confirmed (%1 confirmations)</source> <translation>Potvrdjena (%1 potvrdjenih)</translation> </message> <message> + <source>Conflicted</source> + <translation>Неуслагашен</translation> + </message> + <message> + <source>Immature (%1 confirmations, will be available after %2)</source> + <translation>Није доспео (%1 потврде, биће доступан након %2)</translation> + </message> + <message> <source>Generated but not accepted</source> - <translation>Generisan ali nije prihvaćen</translation> + <translation>Генерисан али није прихваћен</translation> </message> <message> <source>Received with</source> - <translation>Primljen sa</translation> + <translation>Примљен са</translation> </message> <message> <source>Received from</source> - <translation>Primljeno od</translation> + <translation>Примљено од</translation> </message> <message> <source>Sent to</source> - <translation>Poslat ka</translation> + <translation>Послато ка</translation> </message> <message> <source>Payment to yourself</source> - <translation>Isplata samom sebi</translation> + <translation>Уплата самом себи</translation> </message> <message> <source>Mined</source> - <translation>Minirano</translation> + <translation>Рударено</translation> + </message> + <message> + <source>watch-only</source> + <translation>гледај-само</translation> </message> <message> <source>(n/a)</source> @@ -1221,78 +2996,98 @@ </message> <message> <source>(no label)</source> - <translation>(без налепнице)</translation> + <translation>(без ознаке)</translation> </message> <message> <source>Transaction status. Hover over this field to show number of confirmations.</source> - <translation>Status vaše transakcije. Predjite mišem preko ovog polja da bi ste videli broj konfirmacija</translation> + <translation>Статус трансакције. Пређи мишем преко поља за приказ броја трансакција.</translation> </message> <message> <source>Date and time that the transaction was received.</source> - <translation>Datum i vreme primljene transakcije.</translation> + <translation>Датум и време пријема трансакције</translation> </message> <message> <source>Type of transaction.</source> - <translation>Tip transakcije</translation> + <translation>Тип трансакције.</translation> + </message> + <message> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation>Без обзира да ли је у ову трансакције укључена или није - адреса само за гледање.</translation> + </message> + <message> + <source>User-defined intent/purpose of the transaction.</source> + <translation>Намена / сврха трансакције коју одређује корисник.</translation> </message> <message> <source>Amount removed from or added to balance.</source> - <translation>Iznos odbijen ili dodat balansu.</translation> + <translation>Износ одбијен или додат салду.</translation> </message> </context> <context> <name>TransactionView</name> <message> <source>All</source> - <translation>Sve</translation> + <translation>Све</translation> </message> <message> <source>Today</source> - <translation>Danas</translation> + <translation>Данас</translation> </message> <message> <source>This week</source> - <translation>ove nedelje</translation> + <translation>Oве недеље</translation> </message> <message> <source>This month</source> - <translation>Ovog meseca</translation> + <translation>Овог месеца</translation> </message> <message> <source>Last month</source> - <translation>Prošlog meseca</translation> + <translation>Претходног месеца</translation> </message> <message> <source>This year</source> - <translation>Ove godine</translation> + <translation>Ове године</translation> </message> <message> <source>Range...</source> - <translation>Opseg...</translation> + <translation>Опсег...</translation> </message> <message> <source>Received with</source> - <translation>Primljen sa</translation> + <translation>Примљен са...</translation> </message> <message> <source>Sent to</source> - <translation>Poslat ka</translation> + <translation>Послат ка</translation> </message> <message> <source>To yourself</source> - <translation>Vama - samom sebi</translation> + <translation>Теби</translation> </message> <message> <source>Mined</source> - <translation>Minirano</translation> + <translation>Рударено</translation> </message> <message> <source>Other</source> - <translation>Drugi</translation> + <translation>Други</translation> + </message> + <message> + <source>Enter address, transaction id, or label to search</source> + <translation>Унесите адресу, ознаку трансакције, или назив за претрагу</translation> </message> <message> <source>Min amount</source> - <translation>Min iznos</translation> + <translation>Минимални износ</translation> + </message> + <message> + <source>Abandon transaction</source> + <translation>Напусти трансакцију</translation> + </message> + <message> + <source>Increase transaction fee</source> + <translation>Повећај провизију трансакције</translation> </message> <message> <source>Copy address</source> @@ -1300,20 +3095,35 @@ </message> <message> <source>Copy label</source> - <translation>Копирај налепницу -</translation> + <translation>Копирај ознаку</translation> </message> <message> <source>Copy amount</source> - <translation>к</translation> + <translation>Копирај износ</translation> </message> <message> <source>Copy transaction ID</source> <translation>Копирај идентификациони број трансакције</translation> </message> <message> + <source>Copy raw transaction</source> + <translation>Копирајте необрађену трансакцију</translation> + </message> + <message> + <source>Copy full transaction details</source> + <translation>Копирајте потпуне детаље трансакције</translation> + </message> + <message> <source>Edit label</source> - <translation>promeni naziv</translation> + <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> @@ -1321,46 +3131,94 @@ </message> <message> <source>Confirmed</source> - <translation>Potvrdjen</translation> + <translation>Потврђено</translation> + </message> + <message> + <source>Watch-only</source> + <translation>Само-гледање</translation> </message> <message> <source>Date</source> - <translation>datum</translation> + <translation>Датум</translation> </message> <message> <source>Type</source> - <translation>tip</translation> + <translation>Тип</translation> </message> <message> <source>Label</source> - <translation>Налепница</translation> + <translation>Ознака</translation> </message> <message> <source>Address</source> - <translation>Adresa</translation> + <translation>Адреса</translation> + </message> + <message> + <source>ID</source> + <translation>ID</translation> </message> <message> <source>Exporting Failed</source> <translation>Извоз Неуспешан</translation> </message> <message> + <source>There was an error trying to save the transaction history to %1.</source> + <translation>Десила се грешка приликом покушаја да се сними историја трансакција на %1.</translation> + </message> + <message> + <source>Exporting Successful</source> + <translation>Извоз Успешан</translation> + </message> + <message> + <source>The transaction history was successfully saved to %1.</source> + <translation>Историја трансакција је успешно снимљена на %1.</translation> + </message> + <message> <source>Range:</source> - <translation>Opseg:</translation> + <translation>Опсег:</translation> </message> <message> <source>to</source> - <translation>do</translation> + <translation>до</translation> </message> </context> <context> <name>UnitDisplayStatusBarControl</name> - </context> + <message> + <source>Unit to show amounts in. Click to select another unit.</source> + <translation>Јединица у којој се приказују износи. Притисни да се прикаже друга јединица.</translation> + </message> +</context> <context> <name>WalletController</name> - </context> + <message> + <source>Close wallet</source> + <translation>Затвори новчаник</translation> + </message> + <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Да ли сте сигурни да желите да затворите новчаник <i>%1</i>?</translation> + </message> + <message> + <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> + <translation>Услед затварања новчаника на дугачки период времена може се десити да је потребна поновна синхронизација комплетног ланца, уколико је дозвољено резање.</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Затвори све новчанике</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Да ли сигурно желите да затворите све новчанике?</translation> + </message> +</context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>Направи нови ночаник</translation> + </message> +</context> <context> <name>WalletModel</name> <message> @@ -1368,6 +3226,54 @@ <translation>Слање новца</translation> </message> <message> + <source>Fee bump error</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>Do you want to draft a transaction with fee increase?</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>Confirm fee bump</source> + <translation>Потврдите ударну провизију</translation> + </message> + <message> + <source>Can't draft transaction.</source> + <translation>Није могуће саставити трансакцију.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT је копиран</translation> + </message> + <message> + <source>Can't sign transaction.</source> + <translation>Није могуће потписати трансакцију.</translation> + </message> + <message> + <source>Could not commit transaction</source> + <translation>Трансакција није могућа</translation> + </message> + <message> <source>default wallet</source> <translation>подразумевани новчаник</translation> </message> @@ -1376,32 +3282,530 @@ <name>WalletView</name> <message> <source>&Export</source> - <translation>&Izvedi</translation> + <translation>&Извези</translation> </message> <message> <source>Export the data in the current tab to a file</source> <translation>Извези податке из одабране картице у фајлj</translation> </message> <message> + <source>Error</source> + <translation>Грешка</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Није могуће декодирати PSBT из клипборд-а (неважећи base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Учитај Податке Трансакције</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Делимично Потписана Трансакција (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PSBT фајл мора бити мањи од 100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Немогуће декодирати PSBT</translation> + </message> + <message> <source>Backup Wallet</source> - <translation>Backup новчаника</translation> + <translation>Резервна копија новчаника</translation> </message> - </context> + <message> + <source>Wallet Data (*.dat)</source> + <translation>Датотека новчаника (*.dat)</translation> + </message> + <message> + <source>Backup Failed</source> + <translation>Резервна копија није успела</translation> + </message> + <message> + <source>There was an error trying to save the wallet data to %1.</source> + <translation>Десила се грешка приликом покушаја да се сними датотека новчаника на %1.</translation> + </message> + <message> + <source>Backup Successful</source> + <translation>Резервна копија је успела</translation> + </message> + <message> + <source>The wallet data was successfully saved to %1.</source> + <translation>Датотека новчаника је успешно снимљена на %1.</translation> + </message> + <message> + <source>Cancel</source> + <translation>Откажи</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>Дистрибуирано под MIT софтверском лиценцом, погледајте придружени документ %s или %s</translation> + </message> + <message> + <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> + <translation>Скраћивање је конфигурисано испод минимума од %d MiB. Молимо користите већи број.</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>Скраћивање: последња синхронизација иде преко одрезаних података. Потребно је урадити ре-индексирање (преузети комплетан ланац блокова поново у случају одсеченог чвора)</translation> + </message> + <message> + <source>Pruning blockstore...</source> + <translation>Скраћивање спремљених блокова...</translation> + </message> + <message> + <source>Unable to start HTTP server. See debug log for details.</source> + <translation>Стартовање HTTP сервера није могуће. Погледати дневник исправљених грешака за детаље.</translation> + </message> + <message> + <source>The %s developers</source> + <translation>%s девелопери</translation> + </message> + <message> + <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> + <translation>Директоријум података се не може закључати %s. %s је вероватно већ покренут.</translation> + </message> + <message> + <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> + <translation>Не може се обезбедити одређена конекција и да addrman нађе одлазне конекције у исто време.</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>Грешка у читању %s! Сви кључеви су прочитани коректно, али подаци о трансакцији или уноси у адресар могу недостајати или бити нетачни.</translation> + </message> + <message> + <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> + <translation>Молим проверите да су време и датум на вашем рачунару тачни. Уколико је сат нетачан, %s неће радити исправно.</translation> + </message> + <message> + <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> + <translation>Молим донирајте, уколико сматрате %s корисним. Посетите %s за више информација о софтверу.</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>База података о блоковима садржи блок, за који се чини да је из будућности. Ово може бити услед тога што су време и датум на вашем рачунару нису подешени коректно. Покушајте обнову базе података о блоковима, само уколико сте сигурни да су време и датум на вашем рачунару исправни.</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>Ово је тестна верзија пред издавање - користите на ваш ризик - не користити за рударење или трговачку примену</translation> + </message> + <message> + <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> + <translation>Ово је накнада за трансакцију коју можете одбацити уколико је мања од нивоа прашине</translation> + </message> + <message> + <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> + <translation>Блокове није могуће поново репродуковати. Ви ћете морати да обновите базу података користећи -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>Није могуће вратити базу података на стање пре форк-а. Ви ћете морати да урадите поновно преузимање ланца блокова.</translation> + </message> + <message> + <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> + <translation>Упозорење: Изгледа да не постоји пуна сагласност на мрежи. Изгледа да одређени рудари имају проблеме.</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>Упозорење: Изгледа да се ми у потпуности не слажемо са нашим чворовима! Можда постоји потреба да урадите надоградњу, или други чворови морају да ураде надоградњу.</translation> + </message> + <message> + <source>-maxmempool must be at least %d MB</source> + <translation>-maxmempool мора бити минимално %d MB</translation> + </message> + <message> + <source>Cannot resolve -%s address: '%s'</source> + <translation>Не могу решити -%s адреса: '%s'</translation> + </message> + <message> + <source>Change index out of range</source> + <translation>Промењен индекс изван домета</translation> + </message> + <message> + <source>Config setting for %s only applied on %s network when in [%s] section.</source> + <translation>Подешавање конфигурације за %s је само примењено на %s мрежи када је у [%s] секцији.</translation> + </message> + <message> + <source>Copyright (C) %i-%i</source> + <translation>Ауторско право (C) %i-%i</translation> + </message> + <message> + <source>Corrupted block database detected</source> + <translation>Детектована је оштећена база података блокова</translation> + </message> + <message> + <source>Could not find asmap file %s</source> + <translation>Не могу пронаћи датотеку asmap %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Не могу рашчланити датотеку asmap %s</translation> + </message> + <message> + <source>Do you want to rebuild the block database now?</source> + <translation>Да ли желите да сада обновите базу података блокова?</translation> + </message> + <message> + <source>Error initializing block database</source> + <translation>Грешка у иницијализацији базе података блокова</translation> + </message> + <message> + <source>Error initializing wallet database environment %s!</source> + <translation>Грешка код иницијализације окружења базе података новчаника %s!</translation> + </message> + <message> + <source>Error loading %s</source> + <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> + <message> + <source>Error opening block database</source> + <translation>Грешка приликом отварања базе података блокова</translation> + </message> + <message> + <source>Failed to listen on any port. Use -listen=0 if you want this.</source> + <translation>Преслушавање није успело ни на једном порту. Користите -listen=0 уколико желите то.</translation> + </message> + <message> + <source>Failed to rescan the wallet during initialization</source> + <translation>Није успело поновно скенирање новчаника приликом иницијализације.</translation> + </message> + <message> + <source>Importing...</source> + <translation>Увоз у току...</translation> + </message> + <message> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Почетни блок је погрешан или се не може пронаћи. Погрешан datadir за мрежу?</translation> + </message> + <message> + <source>Initialization sanity check failed. %s is shutting down.</source> + <translation>Провера исправности иницијализације није успела. %s се искључује.</translation> + </message> + <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Неважећа P2P дозвола: '%s'</translation> + </message> + <message> + <source>Invalid amount for -%s=<amount>: '%s'</source> + <translation>Неважећи износ за %s=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -discardfee=<amount>: '%s'</source> + <translation>Неважећи износ за -discardfee=<amount>: '%s'</translation> + </message> + <message> + <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> + <translation>Неважећи износ за -fallbackfee=<amount>: '%s'</translation> + </message> + <message> + <source>Specified blocks directory "%s" does not exist.</source> + <translation>Наведени директоријум блокова "%s" не постоји.</translation> + </message> + <message> + <source>Unknown address type '%s'</source> + <translation>Непознати тип адресе '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Непознати тип промене '%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>Not enough file descriptors available.</source> + <translation>Нема довољно доступних дескриптора датотеке.</translation> + </message> + <message> + <source>Prune cannot be configured with a negative value.</source> + <translation>Скраћење се не може конфигурисати са негативном вредношћу.</translation> + </message> + <message> + <source>Prune mode is incompatible with -txindex.</source> + <translation>Мод скраћивања није компатибилан са -txindex.</translation> + </message> + <message> + <source>Replaying blocks...</source> + <translation>Поновно репродуковање блокова...</translation> + </message> + <message> + <source>Rewinding blocks...</source> + <translation>Премотавање блокова...</translation> + </message> + <message> + <source>The source code is available from %s.</source> + <translation>Изворни код је доступан из %s.</translation> + </message> + <message> + <source>Transaction fee and change calculation failed</source> + <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 logging category %s=%s.</source> + <translation>Категорија записа није подржана %s=%s.</translation> + </message> + <message> + <source>Upgrading UTXO database</source> + <translation>Надоградња UTXO базе података</translation> + </message> + <message> + <source>User Agent comment (%s) contains unsafe characters.</source> + <translation>Коментар агента корисника (%s) садржи небезбедне знакове.</translation> + </message> + <message> + <source>Verifying blocks...</source> + <translation>Потврда блокова у току...</translation> + </message> + <message> + <source>Wallet needed to be rewritten: restart %s to complete</source> + <translation>Новчаник треба да буде преписан: поновно покрените %s да завршите</translation> + </message> + <message> + <source>Error: Listening for incoming connections failed (listen returned error %s)</source> + <translation>Грешка: Претрага за долазним конекцијама није успела (претрага враћа грешку %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>Неважећи износ за -maxtxfee=<amount>: '%s' (мора бити minrelay провизија од %s да би се спречило да се трансакција заглави)</translation> + </message> + <message> + <source>The transaction amount is too small to send after the fee has been deducted</source> + <translation>Износ трансакције је толико мали за слање након што се одузме провизија</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>Обновите базу података користећи -reindex да би се вратили у нескраћени мод. Ово ће урадити поновно преузимање комплетног ланца података</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Премало простора на диску!</translation> + </message> + <message> + <source>Error reading from database, shutting down.</source> + <translation>Грешка приликом читања из базе података, искључивање у току.</translation> + </message> + <message> + <source>Error upgrading chainstate database</source> + <translation>Грешка приликом надоградње базе података стања ланца</translation> + </message> + <message> + <source>Error: Disk space is low for %s</source> + <translation>Грешка: Простор на диску је мали за %s</translation> + </message> + <message> + <source>Invalid -onion address or hostname: '%s'</source> + <translation>Неважећа -onion адреса или име хоста: '%s'</translation> + </message> + <message> + <source>Invalid -proxy address or hostname: '%s'</source> + <translation>Неважећа -proxy адреса или име хоста: '%s'</translation> + </message> + <message> + <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <translation>Неважећи износ за -paytxfee=<amount>: '%s' (мора бити бар %s)</translation> + </message> + <message> + <source>Invalid netmask specified in -whitelist: '%s'</source> + <translation>Неважећа мрежна маска наведена у -whitelist: '%s'</translation> + </message> + <message> + <source>Need to specify a port with -whitebind: '%s'</source> + <translation>Ви морате одредити порт са -whitebind: '%s'</translation> + </message> + <message> + <source>Prune mode is incompatible with -blockfilterindex.</source> + <translation>Мод скраћења је некомпатибилна са -blockfilterindex.</translation> + </message> + <message> + <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> + <translation>Смањивање -maxconnections са %d на %d, због ограничења система.</translation> + </message> + <message> + <source>Section [%s] is not recognized.</source> + <translation>Одељак [%s] није препознат.</translation> + </message> + <message> + <source>Signing transaction failed</source> + <translation>Потписивање трансакције није успело</translation> + </message> + <message> + <source>Specified -walletdir "%s" does not exist</source> + <translation>Наведени -walletdir "%s" не постоји</translation> + </message> + <message> + <source>Specified -walletdir "%s" is a relative path</source> + <translation>Наведени -walletdir "%s" је релативна путања</translation> + </message> + <message> + <source>Specified -walletdir "%s" is not a directory</source> + <translation>Наведени -walletdir "%s" није директоријум</translation> + </message> + <message> + <source>The specified config file %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> + <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</source> + <translation>Трансакција превелика.</translation> + </message> + <message> + <source>Unable to bind to %s on this computer (bind returned error %s)</source> + <translation>Није могуће повезати %s на овом рачунару (веза враћа грешку %s)</translation> + </message> + <message> + <source>Unable to create the PID file '%s': %s</source> + <translation>Стварање PID документа '%s': %s није могуће</translation> + </message> + <message> + <source>Unable to generate initial keys</source> + <translation>Генерисање кључева за иницијализацију није могуће</translation> + </message> + <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Непозната вредност -blockfilterindex %s.</translation> + </message> + <message> + <source>Verifying wallet(s)...</source> + <translation>Потврђивање новчаника(а)...</translation> + </message> + <message> + <source>Warning: unknown new rules activated (versionbit %i)</source> + <translation>Упозорење: активирано је ново непознато правило (versionbit %i)</translation> + </message> + <message> + <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> + <translation>-maxtxfee је постављен сувише високо! Овако велике провизије могу бити наплаћене на само једној трансакцији.</translation> + </message> + <message> + <source>This is the transaction fee you may pay when fee estimates are not available.</source> + <translation>Ово је провизија за трансакцију коју можете платити када процена провизије није доступна.</translation> + </message> + <message> + <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> + <translation>Укупна дужина мрежне верзије низа (%i) је већа од максималне дужине (%i). Смањити број или величину корисничких коментара.</translation> + </message> + <message> + <source>%s is set very high!</source> + <translation>%s је постављен врло високо!</translation> + </message> + <message> + <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> + <translation>Грешка приликом учитавања новчаника %s. Наведено је дуплирано име датотеке -wallet.</translation> + </message> + <message> + <source>Starting network threads...</source> + <translation>Покретање мрежних тема...</translation> + </message> + <message> + <source>The wallet will avoid paying less than the minimum relay fee.</source> + <translation>Новчаник ће избећи плаћање износа мањег него што је минимална повезана провизија.</translation> + </message> + <message> + <source>This is the minimum transaction fee you pay on every transaction.</source> + <translation>Ово је минимални износ провизије за трансакцију коју ћете платити на свакој трансакцији.</translation> + </message> + <message> + <source>This is the transaction fee you will pay if you send a transaction.</source> + <translation>Ово је износ провизије за трансакцију коју ћете платити уколико шаљете трансакцију.</translation> + </message> + <message> + <source>Transaction amounts must not be negative</source> + <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> + <message> + <source>Unknown network specified in -onlynet: '%s'</source> + <translation>Непозната мрежа је наведена у -onlynet: '%s'</translation> + </message> + <message> <source>Insufficient funds</source> - <translation>Nedovoljno sredstava</translation> + <translation>Недовољно средстава</translation> + </message> + <message> + <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> + <translation>Процена провизије није успела. Промена провизије током трансакције је онемогућена. Сачекајте неколико блокова или омогућите -fallbackfee.</translation> + </message> + <message> + <source>Warning: Private keys detected in wallet {%s} with disabled private keys</source> + <translation>Упозорење: Приватни кључеви су пронађени у новчанику {%s} са онемогућеним приватним кључевима.</translation> + </message> + <message> + <source>Cannot write to data directory '%s'; check permissions.</source> + <translation>Није могуће извршити упис у директоријум података '%s'; проверите дозволе за упис.</translation> </message> <message> <source>Loading block index...</source> - <translation>Učitavam blok indeksa...</translation> + <translation>Учитавање индекса блокова</translation> </message> <message> <source>Loading wallet...</source> <translation>Новчаник се учитава...</translation> </message> <message> + <source>Cannot downgrade wallet</source> + <translation>Новчаник се не може уназадити</translation> + </message> + <message> <source>Rescanning...</source> <translation>Ponovo skeniram...</translation> </message> diff --git a/src/qt/locale/bitcoin_sr@latin.ts b/src/qt/locale/bitcoin_sr@latin.ts index a80c5a0891..bfed8b96ae 100644 --- a/src/qt/locale/bitcoin_sr@latin.ts +++ b/src/qt/locale/bitcoin_sr@latin.ts @@ -30,6 +30,10 @@ <translation>Briše trenutno izabranu adresu sa liste</translation> </message> <message> + <source>Enter address or label to search</source> + <translation>Unesite adresu ili oznaku za pretragu</translation> + </message> + <message> <source>Export the data in the current tab to a file</source> <translation>Izvoz podataka iz trenutne kartice u datoteku</translation> </message> @@ -128,6 +132,10 @@ <translation>Ponovo unesite pristupnu frazu</translation> </message> <message> + <source>Show passphrase</source> + <translation>Prikaži lozinku</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Šifrujte novčanik</translation> </message> @@ -168,6 +176,22 @@ <translation>Novčanik je šifrovan</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Unesite lozinku u novčanik. <br/>Molimo, koristite lozinku koja ima <b> deset ili više nasumičnih znakova</b>, ili <b>osam ili više reči</b>.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Unesite u novčanik staru lozinku i novu lozinku.</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Novčanik će vam biti šifriran.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Vaš novčanik je sada šifrovan.</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: Ranije rezervne kopije wallet datoteke trebate zameniti sa novo-kreiranom, enkriptovanom wallet datotekom. Iz sigurnosnih razloga, ranije ne-enkriptovane wallet datoteke će postati neupotrebljive čim počnete koristiti novi, enkriptovani novčanik.</translation> </message> @@ -290,6 +314,10 @@ <translation>Otvori &URI...</translation> </message> <message> + <source>Wallet:</source> + <translation>Novčanik:</translation> + </message> + <message> <source>Click to disable network activity.</source> <translation>Odaberite za prekid aktivnosti na mreži.</translation> </message> @@ -386,6 +414,10 @@ <translation>Informacije</translation> </message> <message> + <source>Open Wallet</source> + <translation>Otvori novčanik</translation> + </message> + <message> <source>%1 client</source> <translation>%1 klijent</translation> </message> @@ -456,6 +488,10 @@ </context> <context> <name>CreateWalletDialog</name> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Onemogućite privatne ključeve za ovaj novčanik. Novčanici sa isključenim privatnim ključevima neće imati privatne ključeve i ne mogu imati HD seme ili uvezene privatne ključeve. Ovo je idealno za novčanike samo za gledanje.</translation> + </message> </context> <context> <name>EditAddressDialog</name> @@ -509,6 +545,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -537,26 +576,14 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>Adresa</translation> - </message> - <message> - <source>Amount</source> - <translation>Kolicina</translation> - </message> - <message> - <source>Label</source> - <translation>Oznaka</translation> - </message> - <message> - <source>Message</source> - <translation>Poruka</translation> + <source>Amount:</source> + <translation>Iznos:</translation> </message> <message> - <source>Wallet</source> - <translation>Novčanik</translation> + <source>Wallet:</source> + <translation>Novčanik:</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -841,6 +868,10 @@ <source>Export the data in the current tab to a file</source> <translation>Izvoz podataka iz trenutne kartice u datoteku</translation> </message> + <message> + <source>Error</source> + <translation>Greska</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index e626b1a930..3aa4cb9ce9 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -70,10 +70,6 @@ <translation>Detta är dina Bitcoin-adresser för att skicka betalningar. Kontrollera alltid belopp och mottagaradress innan du skickar bitcoin.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Detta är dina Bitcoinadresser för att ta emot betalningar. Använd knappen 'Skapa ny mottagaradress' på fliken ta emot för att skapa nya adresser .</translation> - </message> - <message> <source>&Copy Address</source> <translation>&Kopiera adress</translation> </message> @@ -483,6 +479,14 @@ Försök igen.</translation> <translation>Uppdaterad</translation> </message> <message> + <source>Node window</source> + <translation>Nod-fönster</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Öppna nodens konsol för felsökning och diagnostik</translation> + </message> + <message> <source>&Sending addresses</source> <translation>Av&sändaradresser</translation> </message> @@ -491,6 +495,10 @@ Försök igen.</translation> <translation>Mottaga&radresser</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Öppna en bitcoin:-URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Öppna plånbok</translation> </message> @@ -618,11 +626,7 @@ Försök igen.</translation> <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Denna plånbok är <b>krypterad</b> och för närvarande <b>låst</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Ett kritiskt fel uppstod. Bitcoin kan inte fortsätta att köra säkert och kommer att avslutas.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -784,7 +788,11 @@ Försök igen.</translation> <source>Create wallet failed</source> <translation>Plånboken kunde inte skapas</translation> </message> - </context> + <message> + <source>Create wallet warning</source> + <translation>Skapa plånboksvarning</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> <message> @@ -804,6 +812,22 @@ Försök igen.</translation> <translation>Kryptera plånbok</translation> </message> <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Stäng av privata nycklar för denna plånbok. Plånböcker med privata nycklar avstängda kommer inte innehålla några privata nycklar alls, och kan inte innehålla vare sig en HD-seed eller importerade privata nycklar. Detta är idealt för plånböcker som endast ska granskas.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Stäng av privata nycklar</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Skapa en tom plånbok. Tomma plånböcker har från början inga privata nycklar eller skript. Privata nycklar och adresser kan importeras, eller en HD-seed kan väljas, vid ett senare tillfälle.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Skapa tom plånbok</translation> + </message> + <message> <source>Create</source> <translation>Skapa</translation> </message> @@ -920,6 +944,10 @@ Försök igen.</translation> <translation>När du trycker OK kommer %1 att börja ladda ner och bearbeta den fullständiga %4-blockkedjan (%2 GB), med början vid de första transaktionerna %3 när %4 först lanserades.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Att återställa detta alternativ påbörjar en omstart av nedladdningen av hela blockkedjan. Det går snabbare att ladda ner hela kedjan först, och gallra den senare. Detta alternativ stänger av vissa avancerade funktioner.</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>Denna första synkronisering är väldigt krävande, och kan påvisa hårdvaruproblem hos din dator som tidigare inte visat sig. Varje gång du kör %1, kommer nerladdningen att fortsätta där den avslutades.</translation> </message> @@ -940,6 +968,10 @@ Försök igen.</translation> <translation>Bitcoin</translation> </message> <message> + <source>Discard blocks after verification, except most recent %1 GB (prune)</source> + <translation>Släng block efter verifiering, förutom de senaste %1 GB (gallra).</translation> + </message> + <message> <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <translation>Minst %1 GB data kommer att sparas i den här katalogen, och de växer över tiden.</translation> </message> @@ -1023,6 +1055,10 @@ Försök igen.</translation> <translation>Dölj</translation> </message> <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Okänd. Synkar huvuden (%1, %2%)...</translation> </message> @@ -1030,6 +1066,10 @@ Försök igen.</translation> <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Öppna bitcoin-URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -1041,6 +1081,10 @@ Försök igen.</translation> <translation>Det gick inte att öppna plånboken</translation> </message> <message> + <source>Open wallet warning</source> + <translation>Öppna plånboksvarning.</translation> + </message> + <message> <source>default wallet</source> <translation>Standardplånbok</translation> </message> @@ -1084,10 +1128,6 @@ Försök igen.</translation> <translation>Visar om den angivna standard-SOCKS5-proxyn används för att nå noder via den här nätverkstypen.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Använd separat SOCKS&5-proxy för att nå noder via Tors dolda tjänster:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Dölj ikonen från systemfältet.</translation> </message> @@ -1220,10 +1260,6 @@ Försök igen.</translation> <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Anslut till Bitcoin-nätverket genom en separat SOCKS5-proxy för dolda tjänster i Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Fönster</translation> </message> @@ -1360,7 +1396,7 @@ Försök igen.</translation> </message> <message> <source>Mined balance that has not yet matured</source> - <translation>Genererat saldo som ännu inte har mognat</translation> + <translation>Grävt saldo som ännu inte har mognat</translation> </message> <message> <source>Balances</source> @@ -1392,13 +1428,28 @@ Försök igen.</translation> </message> <message> <source>Mined balance in watch-only addresses that has not yet matured</source> - <translation>Genererat saldo i granska-bara adresser som ännu inte har mognat</translation> + <translation>Grävt saldo i granska-bara adresser som ännu inte har mognat</translation> </message> <message> <source>Current total balance in watch-only addresses</source> <translation>Aktuellt totalt saldo i granska-bara adresser</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Dialog</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Totalt belopp</translation> + </message> + <message> + <source>or</source> + <translation>eller</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1418,6 +1469,14 @@ Försök igen.</translation> <translation>'bitcoin://' är inte en accepterad URI. Använd 'bitcoin:' istället.</translation> </message> <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Som följd av utbredda säkerhetshål i BIP70, rekommenderas det starkt att en säljares instruktion för dig att byta plånbok ignoreras.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Om du får detta fel borde du be säljaren förse dig med en BIP21-kompatibel URI.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>Ogiltig betalningsadress %1</translation> </message> @@ -1579,6 +1638,10 @@ Försök igen.</translation> <translation>Fel vid skapande av QR-kod från URI.</translation> </message> <message> + <source>QR code support not available.</source> + <translation>Stöd för QR-kod är inte längre tillgängligt.</translation> + </message> + <message> <source>Save QR Code</source> <translation>Spara QR-kod</translation> </message> @@ -1646,10 +1709,6 @@ Försök igen.</translation> <translation>Blockkedja</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Aktuellt antal block</translation> - </message> - <message> <source>Memory Pool</source> <translation>Minnespool</translation> </message> @@ -1694,10 +1753,6 @@ Försök igen.</translation> <translation>Välj en klient för att se detaljerad information.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Vitlistad</translation> - </message> - <message> <source>Direction</source> <translation>Riktning</translation> </message> @@ -1722,6 +1777,10 @@ Försök igen.</translation> <translation>Användaragent</translation> </message> <message> + <source>Node window</source> + <translation>Nod-fönster</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>Öppna felsökningsloggen %1 från aktuell datakatalog. Detta kan ta några sekunder för stora loggfiler.</translation> </message> @@ -1738,10 +1797,6 @@ Försök igen.</translation> <translation>Tjänster</translation> </message> <message> - <source>Ban Score</source> - <translation>Bannlysningspoäng</translation> - </message> - <message> <source>Connection Time</source> <translation>Anslutningstid</translation> </message> @@ -1890,14 +1945,6 @@ Försök igen.</translation> <translation>Utgående</translation> </message> <message> - <source>Yes</source> - <translation>Ja</translation> - </message> - <message> - <source>No</source> - <translation>Nej</translation> - </message> - <message> <source>Unknown</source> <translation>Okänd</translation> </message> @@ -1933,6 +1980,10 @@ Försök igen.</translation> <translation>Ett valfritt belopp att begära. Lämna tomt eller ange noll för att inte begära ett specifikt belopp.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</translation> + </message> + <message> <source>&Create new receiving address</source> <translation>S&kapa ny mottagaradress</translation> </message> @@ -1988,12 +2039,28 @@ Försök igen.</translation> <source>Copy amount</source> <translation>Kopiera belopp</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Kunde inte låsa upp plånboken.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-kod</translation> + <source>Amount:</source> + <translation>Belopp:</translation> + </message> + <message> + <source>Label:</source> + <translation>Etikett:</translation> + </message> + <message> + <source>Message:</source> + <translation>Meddelande:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Plånbok:</translation> </message> <message> <source>Copy &URI</source> @@ -2015,30 +2082,6 @@ Försök igen.</translation> <source>Payment information</source> <translation>Betalinformaton</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Adress</translation> - </message> - <message> - <source>Amount</source> - <translation>Belopp</translation> - </message> - <message> - <source>Label</source> - <translation>Etikett</translation> - </message> - <message> - <source>Message</source> - <translation>Meddelande</translation> - </message> - <message> - <source>Wallet</source> - <translation>Plånbok</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2186,6 +2229,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Damm:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Dölj alternativ för transaktionsavgift</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>När transaktionsvolymen är mindre än utrymmet i blocken kan både brytardatorer och relänoder kräva en minimiavgift. Det är okej att bara betala denna minimiavgift, men du ska vara medveten om att det kan leda till att en transaktion aldrig bekräftas så fort efterfrågan på bitcointransaktioner är större än vad nätverket kan hantera.</translation> </message> @@ -2254,14 +2301,26 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>%1 (%2 block)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Sk&apa Osignerad</translation> + </message> + <message> <source> from wallet '%1'</source> <translation>från plånbok: '%1'</translation> </message> <message> + <source>%1 to '%2'</source> + <translation>%1 till '%2'</translation> + </message> + <message> <source>%1 to %2</source> <translation>%1 till %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Vill du skissa denna transaktion?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Är du säker på att du vill skicka?</translation> </message> @@ -2290,10 +2349,22 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Totalt belopp</translation> </message> <message> + <source>To review recipient list click "Show Details..."</source> + <translation>För att gå igenom mottagarlistan, tryck "Visa Detaljer..."</translation> + </message> + <message> <source>Confirm send coins</source> <translation>Bekräfta att pengar ska skickas</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Bekräfta transaktionsförslag</translation> + </message> + <message> + <source>Send</source> + <translation>Skicka</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Mottagarens adress är ogiltig. Kontrollera igen.</translation> </message> @@ -2389,6 +2460,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Ta bort denna post</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Beloppett att skicka i vald enhet</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>Avgiften dras från beloppet som skickas. Mottagaren kommer att ta emot mindre bitcoin än du angivit i beloppsfältet. Om flera mottagare väljs kommer avgiften att fördelas jämt.</translation> </message> @@ -2515,6 +2590,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Bitcoin-adress som meddelandet signerades med</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Signerat meddelande som ska verifieras</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Verifiera meddelandet för att vara säker på att det signerades med angiven Bitcoin-adress</translation> </message> @@ -2547,6 +2626,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Upplåsningen av plånboken avbröts.</translation> </message> <message> + <source>No error</source> + <translation>Inget fel</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Den privata nyckeln för den angivna adressen är inte tillgänglig.</translation> </message> @@ -2721,6 +2804,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Utmatningsindex</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(Certifikatet verifierades inte)</translation> + </message> + <message> <source>Merchant</source> <translation>Handlare</translation> </message> @@ -2832,7 +2919,7 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f </message> <message> <source>Mined</source> - <translation>Genererade</translation> + <translation>Grävda</translation> </message> <message> <source>watch-only</source> @@ -2915,7 +3002,7 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f </message> <message> <source>Mined</source> - <translation>Genererade</translation> + <translation>Grävda</translation> </message> <message> <source>Other</source> @@ -2959,7 +3046,7 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f </message> <message> <source>Copy full transaction details</source> - <translation>Kopiera alla transaktionsdetaljerna</translation> + <translation>Kopiera alla transaktionsdetaljer</translation> </message> <message> <source>Edit label</source> @@ -3044,15 +3131,19 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Stäng plånboken</translation> </message> <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Är du säker att du vill stänga plånboken <i>%1</i>?</translation> + </message> + <message> <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> - <translation>Om plånboken är stängd under för lång tid kan hela kedjan behöva synkroniseras om, om gallring är aktiverad.</translation> + <translation>Om plånboken är stängd under för lång tid och gallring är aktiverad kan hela kedjan behöva synkroniseras på nytt.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Ingen plånbok har lästs in.</translation> + <source>Create a new wallet</source> + <translation>Skapa ny plånbok</translation> </message> </context> <context> @@ -3074,6 +3165,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Vill du öka avgiften?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Vill du skapa en transaktion med en avgiftsökning?</translation> + </message> + <message> <source>Current fee:</source> <translation>Aktuell avgift:</translation> </message> @@ -3090,6 +3185,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Bekräfta avgiftshöjning</translation> </message> <message> + <source>PSBT copied</source> + <translation>PSBT kopierad</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Kan ej signera transaktion.</translation> </message> @@ -3113,6 +3212,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Exportera informationen i aktuell flik till en fil</translation> </message> <message> + <source>Error</source> + <translation>Fel</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Säkerhetskopiera Plånbok</translation> </message> @@ -3156,10 +3259,6 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Gallring: senaste plånbokssynkroniseringen ligger utanför gallrade data. Du måste använda -reindex (ladda ner hela blockkedjan igen om noden gallrats)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Fel: Ett kritiskt internt fel uppstod, se debug.log för detaljer</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Gallrar blockstore...</translation> </message> @@ -3172,10 +3271,6 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>%s-utvecklarna</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Det går inte att skapa en nyckel för växel-adress. Det finns inga nycklar i den interna nyckelpoolen och det går inte att skapa några nycklar.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Kan inte låsa datakatalogen %s. %s körs förmodligen redan.</translation> </message> @@ -3224,14 +3319,6 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Varning: Vi verkar inte helt överens med våra peers! Du kan behöva uppgradera, eller andra noder kan behöva uppgradera.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d av de senaste 100 blocken har oväntad version</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s är korrupt, räddning misslyckades</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool måste vara minst %d MB</translation> </message> @@ -3312,6 +3399,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Initieringschecken fallerade. %s stängs av.</translation> </message> <message> + <source>Invalid P2P permission: '%s'</source> + <translation>Ogiltigt P2P-tillstånd: '%s'</translation> + </message> + <message> <source>Invalid amount for -%s=<amount>: '%s'</source> <translation>Ogiltigt belopp för -%s=<amount>:'%s'</translation> </message> @@ -3328,6 +3419,14 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Den specificerade mappen för block "%s" existerar inte.</translation> </message> <message> + <source>Unknown address type '%s'</source> + <translation>Okänd adress-typ '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Okänd växel-typ '%s'</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Uppgraderar txindex-databasen</translation> </message> @@ -3336,10 +3435,6 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Läser in P2P-adresser...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Fel: Diskutrymmet är för lågt!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Läser in listan över bannlysningar …</translation> </message> @@ -3377,7 +3472,7 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f </message> <message> <source>Unable to generate keys</source> - <translation>Lyckas inte generera nycklar</translation> + <translation>Det gick inte att skapa nycklar</translation> </message> <message> <source>Unsupported logging category %s=%s.</source> @@ -3510,6 +3605,10 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Det gick inte att skapa ursprungliga nycklar</translation> </message> <message> + <source>Unknown -blockfilterindex value %s.</source> + <translation>Okänt värde för -blockfilterindex '%s'.</translation> + </message> + <message> <source>Verifying wallet(s)...</source> <translation>Verifierar plånbok(er)...</translation> </message> @@ -3518,10 +3617,6 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Varning: okända nya regler aktiverade (versionsbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Töm plånboken på alla transaktioner...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee är väldigt högt satt! Så höga avgifter kan komma att betalas för en enstaka transaktion.</translation> </message> @@ -3534,10 +3629,6 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Total längd på strängen för nätverksversion (%i) överskrider maxlängden (%i). Minska numret eller storleken på uacomments.</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>Varning: Plånboksfilen var korrupt, data har räddats! Den ursprungliga %s har sparas som %s i %s. Om ditt saldo eller transaktioner är felaktiga bör du återställa från en säkerhetskopia.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s är satt väldigt högt!</translation> </message> @@ -3582,10 +3673,6 @@ Notera: Då avgiften beräknas per byte kommer en avgift på 50 satoshi tas ut f <translation>Otillräckligt med bitcoins</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 delning. 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>Avgiftsuppskattning misslyckades. Fallbackfee är inaktiverat. Vänta några block eller aktivera -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_szl.ts b/src/qt/locale/bitcoin_szl.ts index 3fb191c50f..489a873ceb 100644 --- a/src/qt/locale/bitcoin_szl.ts +++ b/src/qt/locale/bitcoin_szl.ts @@ -529,11 +529,7 @@ <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> <context> <name>CoinControlDialog</name> <message> @@ -1055,10 +1051,6 @@ <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> @@ -1127,6 +1119,13 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>abo</translation> + </message> + </context> +<context> <name>PaymentServer</name> <message> <source>Payment request error</source> @@ -1273,10 +1272,6 @@ <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> @@ -1360,14 +1355,6 @@ <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> @@ -1411,12 +1398,24 @@ <source>Copy amount</source> <translation>Kopiyruj kwotã</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Niy idzie było ôdszperować portmanyja.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>Kod QR</translation> + <source>Amount:</source> + <translation>Kwota:</translation> + </message> + <message> + <source>Message:</source> + <translation>Wiadōmość:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Portmanyj:</translation> </message> <message> <source>Copy &URI</source> @@ -1434,30 +1433,6 @@ <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> @@ -1868,6 +1843,10 @@ <translation>Eksportuj dane z aktywnyj szkarty do zbioru</translation> </message> <message> + <source>Error</source> + <translation>Feler</translation> + </message> + <message> <source>Backup Failed</source> <translation>Backup niy podarził sie</translation> </message> @@ -1955,10 +1934,6 @@ <translation>Imyntnŏ dugość kety wersyje (%i) przekrŏczŏ maksymalnõ dopuszczalnõ dugość (%i). Zmyńsz wielość abo miara parametra uacomment.</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> diff --git a/src/qt/locale/bitcoin_ta.ts b/src/qt/locale/bitcoin_ta.ts index 85f7db346f..d35834ef64 100644 --- a/src/qt/locale/bitcoin_ta.ts +++ b/src/qt/locale/bitcoin_ta.ts @@ -70,10 +70,6 @@ <translation>இவை பணம் அனுப்புவதற்கு உங்களின் பிட்காயின் முகவரிகள். பிட்காயின்களை அனுப்புவதற்கு முன் எப்பொழுதும் தொகையும் பெறுதலையும் சரிபார்க்கவும்.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>பிட்காயின் பெறுவதற்காக உங்கள் முகவரி இவை. புதிய முகவரிகளை உருவாக்க 'புதிய முகவரியை உருவாக்கு' என்ற பட்டனை கிளிக் செய்யவும்.</translation> - </message> - <message> <source>&Copy Address</source> <translation>&காபி முகவரி</translation> </message> @@ -482,6 +478,14 @@ <translation>தேதி வரை</translation> </message> <message> + <source>Node window</source> + <translation>நோட் விண்டோ</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>திற நோட் பிழைத்திருத்தம் மற்றும் கண்டறியும் பணியகம்</translation> + </message> + <message> <source>&Sending addresses</source> <translation>முகவரிகள் அனுப்புகிறது</translation> </message> @@ -490,6 +494,10 @@ <translation>முகவரிகள் பெறுதல்</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>திற பிட்காயின்: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>வாலட்டை திற</translation> </message> @@ -617,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Wallet குறியாக்கப்பட்டு தற்போது பூட்டப்பட்டுள்ளது</translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Wallet குறியாக்கப்பட்டு தற்போது பூட்டப்பட்டுள்ளது</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -1111,10 +1115,6 @@ <translation>வழங்கப்பட்ட முன்னிருப்பு SOCKS5 ப்ராக்ஸி இந்த நெட்வொர்க் வகையின் மூலம் சகலருக்கும் சென்றால் பயன்படுத்தப்படுகிறது.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Tor மறைக்கப்பட்ட சேவைகளை வழியாக சகலரையும் அணுக தனித்த SOCKS & 5 ப்ராக்ஸி பயன்படுத்தவும்</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>கணினி தட்டில் இருந்து ஐகானை மறைக்கவும்.</translation> </message> @@ -1247,10 +1247,6 @@ <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> @@ -1425,7 +1421,18 @@ <source>Current total balance in watch-only addresses</source> <translation>தற்போதைய மொத்த சமநிலை வாட்ச் மட்டும் முகவரிகள்</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>முழு தொகை</translation> + </message> + <message> + <source>or</source> + <translation>அல்லது</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1445,6 +1452,10 @@ <translation>'bitcoin: //' சரியான URI அல்ல. அதற்கு பதிலாக 'பிட்கின்:' பயன்படுத்தவும்.</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>பரிவர்த்தனை வேண்டுதலை ஏற்க இயலாது ஏனென்றால் BIP70 ஆதரவு தரவில்லை</translation> + </message> + <message> <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> <translation>பிப்70 இல் உள்ள பரவலான பாதுகாப்பு குறைபாடுகள் காரணமாக, வாலட்டை மாற்றுவதற்கான எந்தவொரு வணிக அறிவுறுத்தல்களும் புறக்கணிக்கப்பட வேண்டும் என்று கடுமையாக பரிந்துரைக்கப்படுகிறது.</translation> </message> @@ -1661,10 +1672,6 @@ <translation>தடுப்பு சங்கிலி</translation> </message> <message> - <source>Current number of blocks</source> - <translation>தொகுதிகள் தற்போதைய எண்</translation> - </message> - <message> <source>Memory Pool</source> <translation>நினைவக குளம்</translation> </message> @@ -1709,10 +1716,6 @@ <translation>விரிவான தகவலைப் பார்வையிட ஒரு சகவரைத் தேர்ந்தெடுக்கவும்.</translation> </message> <message> - <source>Whitelisted</source> - <translation>அனுமதிக்கப்பட்டவை</translation> - </message> - <message> <source>Direction</source> <translation>திசை</translation> </message> @@ -1737,6 +1740,10 @@ <translation>பயனர் முகவர்</translation> </message> <message> + <source>Node window</source> + <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> @@ -1753,10 +1760,6 @@ <translation>சேவைகள்</translation> </message> <message> - <source>Ban Score</source> - <translation>பான் ஸ்கோர்</translation> - </message> - <message> <source>Connection Time</source> <translation>இணைப்பு நேரம்</translation> </message> @@ -1905,14 +1908,6 @@ <translation>வெளி செல்லும்</translation> </message> <message> - <source>Yes</source> - <translation>ஆம்</translation> - </message> - <message> - <source>No</source> - <translation>மறு</translation> - </message> - <message> <source>Unknown</source> <translation>அறியப்படாத</translation> </message> @@ -2003,12 +1998,24 @@ <source>Copy amount</source> <translation>நகல் நகல்</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>பணப்பை திறக்க முடியவில்லை.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR குறியீடு</translation> + <source>Amount:</source> + <translation>விலை</translation> + </message> + <message> + <source>Message:</source> + <translation>செய்தி:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>கைப்பை:</translation> </message> <message> <source>Copy &URI</source> @@ -2030,30 +2037,6 @@ <source>Payment information</source> <translation>கொடுப்பனவு தகவல்</translation> </message> - <message> - <source>URI</source> - <translation>URI</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> </context> <context> <name>RecentRequestsTableModel</name> @@ -2317,6 +2300,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>அனுப்பும் பிட்காயின்களை உறுதிப்படுத்தவும்</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>பரிவர்த்தனை வரைவு உறுதி செய்</translation> + </message> + <message> + <source>Send</source> + <translation>அனுப்புவும்</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>பெறுநரின் முகவரி தவறானது. மீண்டும் சரிபார்க்கவும்.</translation> </message> @@ -2558,6 +2549,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>வாலட் திறத்தல் ரத்து செய்யப்பட்டது.</translation> </message> <message> + <source>No error</source> + <translation>தவறு எதுவுமில்லை</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>உள்ளிட்ட முகவரிக்கான ப்ரைவேட் கீ கிடைக்கவில்லை.</translation> </message> @@ -3042,12 +3037,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>வாலட்டை அதிக நேரம் மூடுவதாலும் ப்ரூனிங் இயக்கப்பட்டாலோ முழு செயினை ரீசிங்க் செய்வதற்கு இது வழிவகுக்கும்.</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>எந்த வாலட்டும் லோட் செய்யப்படவில்லை.</translation> + <source>Create a new wallet</source> + <translation>புதிய வாலட்டை உருவாக்கு</translation> </message> </context> <context> @@ -3085,6 +3080,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>கட்டண ஏற்றத்தை உறுதிப்படுத்தவும்</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>பரிவர்த்தனை செய்ய இயலாது</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>பரிவர்த்தனையில் கையொப்பமிட முடியவில்லை.</translation> </message> @@ -3108,6 +3107,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>தற்போதைய தாவலில் தரவை ஒரு கோப்பிற்கு ஏற்றுமதி செய்க</translation> </message> <message> + <source>Error</source> + <translation>பிழை</translation> + </message> + <message> <source>Backup Wallet</source> <translation>பேக்அப் வாலட்</translation> </message> @@ -3151,10 +3154,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>ப்ரூன்: கடைசி வாலட் ஒத்திசைவு ப்ரூன் தரவுக்கு அப்பாற்பட்டது. நீங்கள் -reindex செய்ய வேண்டும் (ப்ரூன் நோட் உபயோகித்தால் முழு பிளாக்செயினையும் மீண்டும் டவுன்லோட் செய்யவும்)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>பிழை: ஆபத்தான உள் பிழை ஏற்பட்டது, விவரங்களுக்கு debug.log ஐ பார்க்கவும்</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>பிளாக்ஸ்டோர் ப்ரூன் செய்யபடுகிறது...</translation> </message> @@ -3167,10 +3166,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%s டெவலப்பர்கள்</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>மாற்று-முகவரி கீயை உருவாக்க முடியாது. கீ தகவல்தளத்தில் கீகள் இல்லை மற்றும் எந்த கீயையும் உருவாக்க முடியாது.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>தரவு கோப்பகத்தை %s லாக் செய்ய முடியாது. %s ஏற்கனவே இயங்குகிறது.</translation> </message> @@ -3219,14 +3214,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>எச்சரிக்கை: நாங்கள் எங்கள் பீர்களுடன் முழுமையாக உடன்படுவதாகத் தெரியவில்லை! நீங்கள் அப்க்ரேட் செய்ய வேண்டியிருக்கலாம், அல்லது மற்ற நோடுகள் அப்க்ரேட் செய்ய வேண்டியிருக்கலாம்.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>கடைசி 100 தொகுதிகளில் %d எதிர்பாராத பதிப்பைக் கொண்டுள்ளன</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s சிதைந்தது, மீட்பு தோல்வியுற்றது</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-மேக்ஸ்மெம்பூல் குறைந்தது %d எம்பி ஆக இருக்க வேண்டும்</translation> </message> @@ -3331,10 +3318,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>பி2பி முகவரிகள் லோட் செய்யப்படுகிறது...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>பிழை: டிஸ்க் ஸ்பேஸ் மிகக் குறைவாக உள்ளது!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>தடைப்பட்டியல் லோட் செய்யப்படுகிறது...</translation> </message> @@ -3467,10 +3450,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>எச்சரிக்கை: அறியப்படாத புதிய விதிகள் செயல்படுத்தப்பட்டன (வெர்ஷன்பிட் %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>வாலாட்டிலிருந்து அனைத்து பரிவர்த்தனைகளையும் அழிக்கிறது...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee மிக அதிகமாக அமைக்கப்பட்டுள்ளது! இவ்வாறு அதிகமுள்ள கட்டணம் ஒரே பரிவர்த்தனையில் செலுத்தப்படலாம்.</translation> </message> diff --git a/src/qt/locale/bitcoin_te.ts b/src/qt/locale/bitcoin_te.ts index 6080d2e4dc..515e82c54a 100644 --- a/src/qt/locale/bitcoin_te.ts +++ b/src/qt/locale/bitcoin_te.ts @@ -132,10 +132,38 @@ <translation>క్రొత్త సంకేతపదము మరలా ఇవ్వండి</translation> </message> <message> + <source>Show passphrase</source> + <translation>సంకేతపదమును చూపించు</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>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> @@ -148,6 +176,26 @@ <translation>జోలె సంకేతపరబడింది</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>వాలెట్ కోసం క్రొత్త పాస్ఫ్రేజ్ని నమోదు చేయండి.<br/> దయచేసి <b>పది లేదా అంతకంటే ఎక్కువ యాదృచ్ఛిక అక్షరాల</b> పాస్ఫ్రేజ్ని లేదా <b>ఎనిమిది లేదా అంతకంటే ఎక్కువ పదాలను ఉపయోగించండి.</b></translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Enter the old passphrase and new passphrase for the wallet.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>మీ వాలెట్ను గుప్తీకరించడం వల్ల మీ కంప్యూటర్కు హాని కలిగించే మాల్వేర్ దొంగిలించకుండా మీ బిట్కాయిన్లను పూర్తిగా రక్షించలేమని గుర్తుంచుకోండి.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>ఎన్క్రిప్ట్ చేయవలసిన వాలెట్</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>మీ వాలెట్ గుప్తీకరించబోతోంది.</translation> + </message> + <message> <source>Wallet encryption failed</source> <translation>జోలె సంకేతపరచడం విఫలమయ్యింది</translation> </message> @@ -251,6 +299,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -274,23 +325,7 @@ </context> <context> <name>ReceiveRequestDialog</name> - <message> - <source>Address</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> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -431,6 +466,10 @@ <source>Export the data in the current tab to a file</source> <translation>ప్రస్తుతం ఉన్న సమాచారాన్ని ఫైల్ లోనికి ఎగుమతి చేసుకోండి</translation> </message> + <message> + <source>Error</source> + <translation>లోపం</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_th.ts b/src/qt/locale/bitcoin_th.ts index e28c987893..3da787dfb4 100644 --- a/src/qt/locale/bitcoin_th.ts +++ b/src/qt/locale/bitcoin_th.ts @@ -443,11 +443,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>กระเป๋าเงินถูก <b>เข้ารหัส</b> และในปัจจุบัน <b>ล็อค </b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>เกิดข้อผิดพลาดร้ายแรง Bitcoin ไม่สามารถดำเนินการต่อได้อย่างปลอดภัยอีกต่อไปและจะยกเลิก</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -805,10 +801,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>เชื่อมต่อกับ เครือข่าย Bitcoin ผ่านทาง พร้อกซี่ SOCKS5 แยกต่างหาก สำหรับ Tor เซอร์วิส</translation> - </message> - <message> <source>&Window</source> <translation>&วันโดว์</translation> </message> @@ -829,6 +821,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -865,26 +860,14 @@ <source>Copy amount</source> <translation>คัดลอกจำนวนเงิน</translation> </message> -</context> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>ที่อยู่</translation> - </message> - <message> - <source>Amount</source> - <translation>จำนวน</translation> - </message> - <message> - <source>Label</source> - <translation>ฉลาก, ป้าย,</translation> - </message> - <message> - <source>Wallet</source> - <translation>กระเป๋าเงิน</translation> + <source>Amount:</source> + <translation>จำนวน:</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -1057,6 +1040,10 @@ <source>Export the data in the current tab to a file</source> <translation>ส่งออกข้อมูลที่อยู่ในแถบนี้ไปในไฟล์</translation> </message> + <message> + <source>Error</source> + <translation>ข้อผิดพลาด</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts index 1677446993..e2c28fca7c 100644 --- a/src/qt/locale/bitcoin_tr.ts +++ b/src/qt/locale/bitcoin_tr.ts @@ -3,31 +3,31 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Adresi veya etiketi düzenlemek için sağ tıklayın</translation> + <translation>Adres veya etiketi düzenlemek için sağ tıklayın</translation> </message> <message> <source>Create a new address</source> - <translation>Yeni adres oluştur</translation> + <translation>Yeni adres oluşturun</translation> </message> <message> <source>&New</source> - <translation>&Yeni</translation> + <translation>Yeni</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Seçili adresi panoya kopyala</translation> + <translation>Seçili adresi panoya kopyalayın</translation> </message> <message> <source>&Copy</source> - <translation>&Kopyala</translation> + <translation>Kopyala</translation> </message> <message> <source>C&lose</source> - <translation>K&apat</translation> + <translation>Kapat</translation> </message> <message> <source>Delete the currently selected address from the list</source> - <translation>Seçili adresi listeden sil</translation> + <translation>Seçili adesi listeden silin</translation> </message> <message> <source>Enter address or label to search</source> @@ -35,51 +35,44 @@ </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> + <translation>Geçerli sekmedeki veriyi bir dosyaya dışa aktarın</translation> </message> <message> <source>&Export</source> - <translation>&Dışa Aktar</translation> + <translation>Dışa aktar</translation> </message> <message> <source>&Delete</source> - <translation>&Sil</translation> + <translation>Sil</translation> </message> <message> <source>Choose the address to send coins to</source> - <translation>koinlerin gönderileceği adresi seçin</translation> - </message> - <message> - <source>Choose the address to receive coins with</source> - <translation>Alıcı adresi seçiniz</translation> + <translation>Coin gönderilecek adresi seçiniz</translation> </message> <message> <source>C&hoose</source> - <translation>Seçim</translation> + <translation>S&ç</translation> </message> <message> <source>Sending addresses</source> - <translation>Gönderilen Adresler</translation> + <translation>Gönderici adresler</translation> </message> <message> <source>Receiving addresses</source> - <translation>Alınan Adresler</translation> + <translation>Alıcı adresler</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>Bunlar ödeme göndermek için gereken Bitcoin adreslerinizdir. Para göndermeden önce her zaman miktarı ve alıcı adresi kontrol edin.</translation> - </message> - <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</translation> + <translation>Bunlar Bitcoinleriniz için gönderici adreslerinizdir. +Gönderim yapmadan önce her zaman tutarı ve alıcı adresi kontrol ediniz.</translation> </message> <message> <source>&Copy Address</source> - <translation>Adresi Kopyala</translation> + <translation>Adresi kopyala</translation> </message> <message> <source>Copy &Label</source> - <translation>Kopyala ve Etiketle</translation> + <translation>Etiketi kopyala</translation> </message> <message> <source>&Edit</source> @@ -87,30 +80,26 @@ </message> <message> <source>Export Address List</source> - <translation>Adres Listesini Dışar Aktar</translation> + <translation>Adres Listesini Dışa Aktar</translation> </message> <message> <source>Comma separated file (*.csv)</source> - <translation>Virgül ile ayrılmış dosya (*.csv)</translation> + <translation>Virgülle ayrılmış dosya (*.csv)</translation> </message> <message> <source>Exporting Failed</source> - <translation>Dışa Aktarma Başarısız</translation> - </message> - <message> - <source>There was an error trying to save the address list to %1. Please try again.</source> - <translation>Adres listesini %1'e kaydederken bir hata oluştu. Lütfen tekrar deneyin.</translation> + <translation>Dışa Aktarım Başarısız Oldu</translation> </message> -</context> + </context> <context> <name>AddressTableModel</name> <message> <source>Label</source> - <translation>etiket</translation> + <translation>Etiket</translation> </message> <message> <source>Address</source> - <translation>adres</translation> + <translation>ADres</translation> </message> <message> <source>(no label)</source> @@ -120,12 +109,8 @@ <context> <name>AskPassphraseDialog</name> <message> - <source>Passphrase Dialog</source> - <translation>Parola Diyaloğu</translation> - </message> - <message> <source>Enter passphrase</source> - <translation>Parolayı girin</translation> + <translation>Parolanızı giriniz.</translation> </message> <message> <source>New passphrase</source> @@ -133,43 +118,36 @@ </message> <message> <source>Repeat new passphrase</source> - <translation>Yeni parolayı tekrarla</translation> + <translation>Yeni parolanızı tekrar ediniz</translation> </message> <message> <source>Show passphrase</source> - <translation>Show passphrase</translation> + <translation>Parolayı göster</translation> </message> <message> <source>Encrypt wallet</source> - <translation>Cüzdanı Şifrele</translation> + <translation>Cüzdan şifrele</translation> </message> <message> <source>This operation needs your wallet passphrase to unlock the wallet.</source> - <translation>Bu işlem, cüzdan kilidinizi açmak için parolanıza ihtiyaç duyuyor</translation> + <translation>Bu işlemi yapabilmek için cüzdan parolanızı girmeniz gerekmektedir +Cüzdan kilidini aç.</translation> </message> <message> <source>Unlock wallet</source> - <translation>Cüzdanı Kilitle</translation> - </message> - <message> - <source>This operation needs your wallet passphrase to decrypt the wallet.</source> - <translation>Bu işlem, cüzdan kilidinizi açmak için parolanıza ihtiyaç duyuyor</translation> + <translation>Cüzdan kilidini aç</translation> </message> <message> <source>Decrypt wallet</source> - <translation>Cüzdanın Şifresini Çöz</translation> + <translation>cüzdan şifresini çöz</translation> </message> <message> <source>Change passphrase</source> - <translation>Parolayı değiştir</translation> + <translation>Parola değiştir</translation> </message> <message> <source>Confirm wallet encryption</source> - <translation>Cüzdan Şifrelemesini Onaylayın</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>Uyarı: Eğer cüzdanınızı şifreleyip parolanızı kaybederseniz (unutursanız) , <b>BÜTÜN BITCOIN'LERINIZI KAYBEDECEKSINIZ</b>!</translation> + <translation>Cüzdan şifrelemeyi onayla</translation> </message> <message> <source>Are you sure you wish to encrypt your wallet?</source> @@ -177,105 +155,69 @@ </message> <message> <source>Wallet encrypted</source> - <translation>Cüzdan Şifrelendi</translation> - </message> - <message> - <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</translation> - </message> - <message> - <source>Enter the old passphrase and new passphrase for the wallet.</source> - <translation>Enter the old passphrase and new passphrase for the wallet.</translation> - </message> - <message> - <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> - <translation>Cüzdanınızı şifrelemenin, bitcoinlerinizin bilgisayara bulaşan kötücül bir yazılım tarafından çalınmaya karşı tamamen koruyamayacağını unutmayınız.</translation> - </message> - <message> - <source>Wallet to be encrypted</source> - <translation>Wallet to be encrypted</translation> + <translation>Cüzdan şifrelendi</translation> </message> <message> <source>Your wallet is about to be encrypted. </source> - <translation>Your wallet is about to be encrypted. </translation> + <translation>Cüzdanınız şifrelenmek üzere</translation> </message> <message> <source>Your wallet is now encrypted. </source> - <translation>Your wallet is now encrypted. </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>ÖNEMLİ: Yeni oluşturduğunuz şifrelenmiş cüzdan dosyasını önceki yedeklenmiş cüzdan dosyasıyla değiştirmeniz gerekmektedir. Güvenlik sebeplerinden dolayı yeni, şifrelenmiş cüzdanınızı kullanmaya başlar başlamaz önceki şifrelenmemiş cüzdan yedekleri kullanılmaz hale gelecektir.</translation> + <translation>Cüzdanınız şu an şifrelenmiş</translation> </message> <message> <source>Wallet encryption failed</source> <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> - <message> <source>Wallet unlock failed</source> - <translation>Cüzdan Kilidi Açma Hatası</translation> - </message> - <message> - <source>The passphrase entered for the wallet decryption was incorrect.</source> - <translation>Cüzdan şifresinin açılması için girilen parola yanlıştı.</translation> - </message> - <message> - <source>Wallet decryption failed</source> - <translation>Cüzdan şifresinin açılması başarısız oldu</translation> + <translation>Cüzdan kilidi açma başarız oldu</translation> </message> <message> <source>Wallet passphrase was successfully changed.</source> - <translation>Cüzdan parolası başarılı bir şekilde değiştirildi.</translation> + <translation>Cüzdan parolası başarılı bir şekilde değiştirildi</translation> </message> <message> <source>Warning: The Caps Lock key is on!</source> - <translation>Dikkat! Caps Lock tuşunuz açık!</translation> + <translation>Uyarı: Caps lock açık</translation> </message> </context> <context> <name>BanTableModel</name> <message> <source>IP/Netmask</source> - <translation>IP/Ağ Maskesi</translation> + <translation>İP/Ağ maskesi</translation> </message> <message> <source>Banned Until</source> - <translation>Şu zamana kadar yasaklı:</translation> + <translation>Kadar Yasaklı</translation> </message> </context> <context> <name>BitcoinGUI</name> <message> <source>Sign &message...</source> - <translation>İmza &mesaj</translation> + <translation>&Mesajı imzala ...</translation> </message> <message> <source>Synchronizing with network...</source> - <translation>Ağ ile bağlantı kuruluyor...</translation> + <translation>Ağ ile senkronize ediliyor...</translation> </message> <message> <source>&Overview</source> - <translation>&Genel bakış</translation> + <translation>Genel durum</translation> </message> <message> <source>Show general overview of wallet</source> - <translation>Cüzdana genel bakışı göster</translation> + <translation>Cüzdan genel durumunu göster</translation> </message> <message> <source>&Transactions</source> - <translation>&İşlemler</translation> + <translation>İşlemler</translation> </message> <message> <source>Browse transaction history</source> - <translation>İşlem geçmişinize göz atın</translation> + <translation>İşlem geçişini görüntüle</translation> </message> <message> <source>E&xit</source> @@ -283,59 +225,55 @@ </message> <message> <source>Quit application</source> - <translation>Başvuruyu iptal edin</translation> - </message> - <message> - <source>&About %1</source> - <translation>Hakkında%1</translation> + <translation>Uygulamayı kapat</translation> </message> <message> <source>Show information about %1</source> - <translation>%1 hakkındaki bilgileri görüntüle</translation> + <translation>%1 hakkındaki bilgileri göster</translation> </message> <message> <source>About &Qt</source> - <translation>Qt Hakkında</translation> + <translation>&Qt hakkında</translation> </message> <message> <source>Show information about Qt</source> - <translation>Qt hakkındaki bilgileri görüntüleyin</translation> + <translation>Qt hakkındaki bilgileri göster</translation> </message> <message> <source>&Options...</source> - <translation>&Seçenekler</translation> + <translation>Seçenekler</translation> </message> <message> <source>Modify configuration options for %1</source> - <translation>%1 için yapılandırma ayarlarını değiştir</translation> + <translation>%1 için yapılandırma seçeneklerini değiştirin</translation> </message> <message> <source>&Encrypt Wallet...</source> - <translation>&Cüzdan Şifreleme</translation> + <translation>Cüzdan &Şifrelemek...</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>&Cüzdan Yedekleme</translation> + <translation>Cüzdanı &Yedekle</translation> </message> <message> <source>&Change Passphrase...</source> - <translation>&Parolayı Değiştir...</translation> + <translation>Parola &Değiştir...</translation> </message> <message> <source>Open &URI...</source> - <translation>URI'yi aç</translation> + <translation>&URI aç...</translation> </message> <message> <source>Create Wallet...</source> - <translation>Create Wallet...</translation> + <translation>Cüzdan oluştur</translation> </message> <message> <source>Create a new wallet</source> - <translation>Create a new wallet</translation> + <translation>Yeni bir cüzdan oluştur</translation> </message> <message> <source>Wallet:</source> - <translation>Cüzdan:</translation> + <translation>Cüzdan</translation> </message> <message> <source>Click to disable network activity.</source> @@ -343,39 +281,23 @@ </message> <message> <source>Network activity disabled.</source> - <translation>Ağ etkinliği devre dışı.</translation> + <translation>Network aktivitesi devre dışı bırakıldı</translation> </message> <message> <source>Click to enable network activity again.</source> - <translation>Ağ aktivitesini tekrar başlatmak için tıklayın.</translation> + <translation>Network activitesini serbest bırakmak için tıklayınız</translation> </message> <message> <source>Syncing Headers (%1%)...</source> - <translation>Üstbilgiler Senkronize Ediliyor (%1%)...</translation> + <translation>Bağlantılar senkronize ediliyor (%1%)...</translation> </message> <message> <source>Reindexing blocks on disk...</source> - <translation>Bloklar disk üzerinde 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>Bitcoin adresine madeni para gönderin</translation> - </message> - <message> - <source>Backup wallet to another location</source> - <translation>Cüzdanınızı başka bir lokasyona yedekleyin</translation> - </message> - <message> - <source>Change the passphrase used for wallet encryption</source> - <translation>Cüzdan şifrelemesi için kullanılan parolayı değiştir</translation> + <translation>Diskteki blokları yeniden indeksleme ...</translation> </message> <message> <source>&Verify message...</source> - <translation>Onay mesajı...</translation> + <translation>Mesajı doğrula</translation> </message> <message> <source>&Send</source> @@ -383,7 +305,7 @@ </message> <message> <source>&Receive</source> - <translation>Al</translation> + <translation>&Teslim alınan</translation> </message> <message> <source>&Show / Hide</source> @@ -391,79 +313,27 @@ </message> <message> <source>Show or hide the main Window</source> - <translation>Ana pencereyi göster ya da gizle</translation> - </message> - <message> - <source>Encrypt the private keys that belong to your wallet</source> - <translation>Cüzdanınıza ait özel anahtarları şifreleyin</translation> - </message> - <message> - <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>İletileri adreslerin size ait olduğunu ispatlamak için Bitcoin adresleri ile imzala</translation> - </message> - <message> - <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>Belirtilen Bitcoin adresleri ile imzalandıklarından emin olmak için iletileri kontrol et</translation> + <translation>Ana pencereyi göster ve ya gizle</translation> </message> <message> <source>&File</source> - <translation>&Dosya</translation> + <translation>Dosya</translation> </message> <message> <source>&Settings</source> - <translation>&Ayarlar</translation> + <translation>Ayarlar</translation> </message> <message> <source>&Help</source> - <translation>&Yardım</translation> + <translation>Yardım</translation> </message> <message> <source>Tabs toolbar</source> - <translation>Sekme araç çubuğu</translation> - </message> - <message> - <source>Request payments (generates QR codes and bitcoin: URIs)</source> - <translation>Ödeme talep et (QR kodu ve bitcoin URI'si oluşturur)</translation> - </message> - <message> - <source>Show the list of used sending addresses and labels</source> - <translation>Kullanılan gönderim adreslerinin ve etiketlerinin listesini göster</translation> - </message> - <message> - <source>Show the list of used receiving addresses and labels</source> - <translation>Kullanılan alış adreslerinin ve etiketlerinin listesini göster</translation> + <translation>Araç çubuğu sekmeleri</translation> </message> <message> <source>&Command-line options</source> - <translation>Komut satırı ayarları</translation> - </message> - <message numerus="yes"> - <source>%n active connection(s) to Bitcoin network</source> - <translation><numerusform>Bitcoin şebekesine %n faal bağlantı</numerusform><numerusform>Bitcoin ağına %n etkin bağlantı var</numerusform></translation> - </message> - <message> - <source>Indexing blocks on disk...</source> - <translation>Bloklar disk üzerinde indeksleniyor...</translation> - </message> - <message> - <source>Processing blocks on disk...</source> - <translation>Bloklar diske işleniyor...</translation> - </message> - <message numerus="yes"> - <source>Processed %n block(s) of transaction history.</source> - <translation><numerusform>Muamele tarihçesinden %n blok işlendi.</numerusform><numerusform>İşlem tarihçesinden %n blok işlendi</numerusform></translation> - </message> - <message> - <source>%1 behind</source> - <translation>%1 geride</translation> - </message> - <message> - <source>Last received block was generated %1 ago.</source> - <translation>Son alınan blok %1 önce oluşturulmuştu.</translation> - </message> - <message> - <source>Transactions after this will not yet be visible.</source> - <translation>Bundan sonraki işlemler henüz görüntülenemez.</translation> + <translation>Komut-satırı seçenekleri</translation> </message> <message> <source>Error</source> @@ -482,28 +352,8 @@ <translation>Güncel</translation> </message> <message> - <source>Node window</source> - <translation>Node window</translation> - </message> - <message> - <source>Open node debugging and diagnostic console</source> - <translation>Open node debugging and diagnostic console</translation> - </message> - <message> - <source>&Sending addresses</source> - <translation>&Sending addresses</translation> - </message> - <message> - <source>&Receiving addresses</source> - <translation>&Receiving addresses</translation> - </message> - <message> - <source>Open a bitcoin: URI</source> - <translation>Open a bitcoin: URI</translation> - </message> - <message> <source>Open Wallet</source> - <translation>Cüzdanı Aç</translation> + <translation>Cüzdanı aç</translation> </message> <message> <source>Open a wallet</source> @@ -511,23 +361,19 @@ </message> <message> <source>Close Wallet...</source> - <translation>Cüzdanı Kapat...</translation> + <translation>Çüzdan kapat</translation> </message> <message> <source>Close wallet</source> - <translation>Cüzdanı Kapat</translation> - </message> - <message> - <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> - <translation>Olası Bitcoin komut satırı seçeneklerinin listesini görmek için %1 yardım mesajını göster</translation> + <translation>Cüzdan kapat</translation> </message> <message> <source>default wallet</source> - <translation>varsayılan cüzdan</translation> + <translation>Varsayılan cüzdan</translation> </message> <message> <source>No wallets available</source> - <translation>No wallets available</translation> + <translation>Erişilebilir cüzdan yok</translation> </message> <message> <source>&Window</source> @@ -539,171 +385,40 @@ </message> <message> <source>Zoom</source> - <translation>Zoom</translation> + <translation>Yakınlaştır</translation> </message> <message> <source>Main Window</source> - <translation>Main Window</translation> + <translation>Ana Pencere</translation> </message> - <message> - <source>%1 client</source> - <translation>%1 istemci</translation> - </message> - <message> - <source>Connecting to peers...</source> - <translation>Eşlere bağlanılıyor...</translation> - </message> - <message> - <source>Catching up...</source> - <translation>Aralık kapatılıyor...</translation> - </message> - <message> - <source>Error: %1</source> - <translation>Hata: %1</translation> - </message> - <message> - <source>Warning: %1</source> - <translation>Warning: %1</translation> - </message> - <message> - <source>Date: %1 -</source> - <translation>Tarih %1</translation> - </message> - <message> - <source>Amount: %1 -</source> - <translation>Tutar: %1 -</translation> - </message> - <message> - <source>Wallet: %1 -</source> - <translation>Cüzdan: %1 -</translation> - </message> - <message> - <source>Type: %1 -</source> - <translation>Tür: %1 -</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>İşlem gönderildi</translation> - </message> - <message> - <source>Incoming transaction</source> - <translation>Gelen işlem</translation> - </message> - <message> - <source>HD key generation is <b>enabled</b></source> - <translation>HD anahtar üretimi<b>aktif</b></translation> - </message> - <message> - <source>HD key generation is <b>disabled</b></source> - <translation>HD anahtar üretimi <b>pasif</b></translation> - </message> - <message> - <source>Private key <b>disabled</b></source> - <translation>Private key <b>disabled</b></translation> - </message> - <message> - <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> - <translation>Cüzdan <b>şifrelenmiştir</b> ve şu anda <b>kilidi açıktır</b></translation> - </message> - <message> - <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> - <translation>Cüzdan <b>şifrelenmiştir</b> ve şu anda <b>kilitlidir</b></translation> - </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Ölümcül bir hata oluştu. Bitcoin yazılımı artık güvenli bir şekilde çalışmaya devam edemediği için kapatılacaktır.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> - <source>Coin Selection</source> - <translation>Bitcoin Seçimi</translation> - </message> - <message> <source>Quantity:</source> - <translation>Miktar:</translation> - </message> - <message> - <source>Bytes:</source> - <translation>Bayt</translation> + <translation>Miktar</translation> </message> <message> <source>Amount:</source> - <translation>Tutar:</translation> + <translation>Miktar</translation> </message> <message> <source>Fee:</source> - <translation>Ücret:</translation> - </message> - <message> - <source>Dust:</source> - <translation>Toz:</translation> - </message> - <message> - <source>After Fee:</source> - <translation>Ücretten sonra kalan:</translation> + <translation>Ücret</translation> </message> <message> <source>Change:</source> - <translation>Değişen:</translation> - </message> - <message> - <source>(un)select all</source> - <translation>tümünü seç(me)</translation> - </message> - <message> - <source>Tree mode</source> - <translation>Ağaç kipi</translation> - </message> - <message> - <source>List mode</source> - <translation>Listeleme modu</translation> + <translation>Değiştir</translation> </message> <message> <source>Amount</source> - <translation>Tutar</translation> - </message> - <message> - <source>Received with label</source> - <translation>Şu etiketle alındı</translation> - </message> - <message> - <source>Received with address</source> - <translation>Şu adresle alındı</translation> + <translation>Mitar</translation> </message> <message> <source>Date</source> <translation>Tarih</translation> </message> <message> - <source>Confirmations</source> - <translation>Onaylamalar</translation> - </message> - <message> - <source>Confirmed</source> - <translation>Kabul edilen</translation> - </message> - <message> <source>Copy address</source> <translation>Adresi kopyala</translation> </message> @@ -713,19 +428,11 @@ </message> <message> <source>Copy amount</source> - <translation>Tutarı kopyala</translation> + <translation>Miktar kopyala</translation> </message> <message> <source>Copy transaction ID</source> - <translation>İşlem ID'sini kopyala</translation> - </message> - <message> - <source>Lock unspent</source> - <translation>Harcanmamışı kilitle</translation> - </message> - <message> - <source>Unlock unspent</source> - <translation>Harcanmamışın kilidini aç</translation> + <translation>İşlem numarasını kopyala</translation> </message> <message> <source>Copy quantity</source> @@ -736,527 +443,130 @@ <translation>Ücreti kopyala</translation> </message> <message> - <source>Copy after fee</source> - <translation>Ücretten sonrasını kopyala</translation> - </message> - <message> - <source>Copy bytes</source> - <translation>Baytları kopyala</translation> - </message> - <message> - <source>Copy dust</source> - <translation>Tozu kopyala</translation> - </message> - <message> - <source>Copy change</source> - <translation>Para üstünü kopyala</translation> - </message> - <message> - <source>(%1 locked)</source> - <translation>(%1 kilitli)</translation> - </message> - <message> <source>yes</source> - <translation>Evet</translation> + <translation>evet</translation> </message> <message> <source>no</source> - <translation>Hayır</translation> - </message> - <message> - <source>This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> - <translation>Eğer herhangi bir alıcı mevcut toz eşiğinden daha düşük bir tutar alırsa bu etiket kırmızıya dönüşür.</translation> - </message> - <message> - <source>Can vary +/- %1 satoshi(s) per input.</source> - <translation>Girdi başına +/- %1 satoshi değişebilir.</translation> + <translation>hayır</translation> </message> <message> <source>(no label)</source> <translation>(etiket yok)</translation> </message> <message> - <source>change from %1 (%2)</source> - <translation>%1 ögesinden para üstü (%2)</translation> - </message> - <message> <source>(change)</source> - <translation>(para üstü)</translation> + <translation>(değiştir)</translation> </message> </context> <context> <name>CreateWalletActivity</name> <message> - <source>Creating Wallet <b>%1</b>...</source> - <translation>Creating Wallet <b>%1</b>...</translation> - </message> - <message> - <source>Create wallet failed</source> - <translation>Create wallet failed</translation> - </message> - <message> <source>Create wallet warning</source> - <translation>Create wallet warning</translation> + <translation>Cüzdan oluşturma uyarısı</translation> </message> </context> <context> <name>CreateWalletDialog</name> <message> <source>Create Wallet</source> - <translation>Create Wallet</translation> + <translation>Cüzdan oluştur</translation> </message> <message> <source>Wallet Name</source> - <translation>Wallet Name</translation> - </message> - <message> - <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> - <translation>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</translation> + <translation>Cüzdan ismi</translation> </message> <message> <source>Encrypt Wallet</source> - <translation>Encrypt Wallet</translation> - </message> - <message> - <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> - <translation>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</translation> - </message> - <message> - <source>Disable Private Keys</source> - <translation>Disable Private Keys</translation> - </message> - <message> - <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> - <translation>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</translation> - </message> - <message> - <source>Make Blank Wallet</source> - <translation>Make Blank Wallet</translation> + <translation>Cüzdanı şifrele</translation> </message> <message> <source>Create</source> - <translation>Create</translation> + <translation>Oluştur</translation> </message> </context> <context> <name>EditAddressDialog</name> <message> <source>Edit Address</source> - <translation>Adresi Düzenle</translation> + <translation>Adresi düzenle</translation> </message> <message> <source>&Label</source> <translation>Etiket</translation> </message> <message> - <source>The label associated with this address list entry</source> - <translation>Bu adres listesi girdisi ile ilişkili etiket</translation> - </message> - <message> - <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> - <translation>Bu adres listesi girdisi ile ilişkili adres. Sadece gönderme adresleri için değiştirilebilir.</translation> - </message> - <message> <source>&Address</source> <translation>Adres</translation> </message> - <message> - <source>New sending address</source> - <translation>Yeni gönderim adresi</translation> - </message> - <message> - <source>Edit receiving address</source> - <translation>Alış adresini düzenleyin</translation> - </message> - <message> - <source>Edit sending address</source> - <translation>Gönderim adresini düzenleyin</translation> - </message> - <message> - <source>The entered address "%1" is not a valid Bitcoin address.</source> - <translation>Girilen adres "%1" Bitcoin adresiyle eşleşmiyor.</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>The entered address "%1" is already in the address book with label "%2".</source> - <translation>girilen "%1" adresi "%2" etiketli adres defterinde zaten var.</translation> - </message> - <message> - <source>Could not unlock wallet.</source> - <translation>Cüzdan kilidi açılamadı.</translation> - </message> - <message> - <source>New key generation failed.</source> - <translation>Yeni anahtar üretimi başarısız.</translation> - </message> -</context> + </context> <context> <name>FreespaceChecker</name> <message> - <source>A new data directory will be created.</source> - <translation>Yeni bir veri klasörü oluşturulacaktır.</translation> - </message> - <message> <source>name</source> - <translation>isim</translation> - </message> - <message> - <source>Directory already exists. Add %1 if you intend to create a new directory here.</source> - <translation>Klasör zaten mevcuttur. Burada yeni bir klasör oluşturmak istiyorsanız, %1 ekleyiniz.</translation> - </message> - <message> - <source>Path already exists, and is not a directory.</source> - <translation>Erişim yolu zaten mevcuttur ve klasör değildir.</translation> - </message> - <message> - <source>Cannot create data directory here.</source> - <translation>Burada veri klasörü oluşturulamaz.</translation> + <translation>İsim</translation> </message> -</context> + </context> <context> <name>HelpMessageDialog</name> <message> <source>version</source> - <translation>versiyon</translation> - </message> - <message> - <source>About %1</source> - <translation>Hakkında %1</translation> + <translation>Versiyon</translation> </message> <message> <source>Command-line options</source> - <translation>Komut satırı ayarları</translation> + <translation>Komut-satırı seçenekleri</translation> </message> </context> <context> <name>Intro</name> <message> <source>Welcome</source> - <translation>Hoş geldiniz</translation> - </message> - <message> - <source>Welcome to %1.</source> - <translation>%1'a hoşgeldiniz.</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>Bu programın ilk kez başlatılmasından dolayı %1 yazılımının verilerini nerede saklayacağını seçebilirsiniz.</translation> - </message> - <message> - <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> - <translation>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</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>Bu başlangıç senkronizasyonu çok zorlayıcıdır ve bilgisayarınızdaki daha önce fark edilmemiş olan donanım sorunlarını ortaya çıkarabilir. %1'i her çalıştırdığınızda, kaldığı yerden devam edecektir.</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>Blok zinciri saklamayı sınırlamayı seçtiyseniz (budama), geçmiş veriler yine de indirilmeli ve işlenmelidir, ancak disk kullanımınızı düşük tutmak için daha sonra silinmelidir.</translation> - </message> - <message> - <source>Use the default data directory</source> - <translation>Varsayılan veri klasörünü kullan</translation> - </message> - <message> - <source>Use a custom data directory:</source> - <translation>Özel bir veri klasörü kullan:</translation> + <translation>Hoş geldiniz </translation> </message> <message> <source>Bitcoin</source> - <translation>Bitcoin -</translation> - </message> - <message> - <source>Discard blocks after verification, except most recent %1 GB (prune)</source> - <translation>Discard blocks after verification, except most recent %1 GB (prune)</translation> - </message> - <message> - <source>At least %1 GB of data will be stored in this directory, and it will grow over time.</source> - <translation>Bu dizinde en az %1 GB lık veri depolanacak ve zamanla büyüyecek.</translation> - </message> - <message> - <source>Approximately %1 GB of data will be stored in this directory.</source> - <translation>Yaklaşık %1 GB veri bu dizinde depolanacak.</translation> - </message> - <message> - <source>%1 will download and store a copy of the Bitcoin block chain.</source> - <translation>%1 lik Bitcoin blok zinciri nin bir kopyasını indirecek ve depolayacak.</translation> - </message> - <message> - <source>The wallet will also be stored in this directory.</source> - <translation>Cüzdan da bu dizinde depolanacaktır.</translation> - </message> - <message> - <source>Error: Specified data directory "%1" cannot be created.</source> - <translation>Hata: belirtilen "%1" veri klasörü oluşturulamaz.</translation> + <translation>Bitcoin</translation> </message> <message> <source>Error</source> <translation>Hata</translation> </message> - <message numerus="yes"> - <source>%n GB of free space available</source> - <translation><numerusform>%n GB boş alan mevcuttur</numerusform><numerusform>%n GB boş alan mevcuttur</numerusform></translation> - </message> - <message numerus="yes"> - <source>(of %n GB needed)</source> - <translation><numerusform>(gereken %n GB alandan)</numerusform><numerusform>(gereken %n GB alandan)</numerusform></translation> - </message> - <message numerus="yes"> - <source>(%n GB needed for full chain)</source> - <translation><numerusform>(%n GB needed for full chain)</numerusform><numerusform>(%n GB needed for full chain)</numerusform></translation> - </message> -</context> + </context> <context> <name>ModalOverlay</name> <message> - <source>Form</source> - <translation>Form</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>Son işlemler henüz görünmeyebilir ve bu nedenle cüzdanınızın bakiyesi yanlış olabilir. Bu bilgiler, aşağıda detaylandırıldığı gibi, cüzdanınız bitcoin ağı ile senkronizasyonunu tamamladığında doğru olacaktır.</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>Henüz görüntülenmeyen işlemlerden etkilenen bitcoinleri harcama girişiminde bulunmak ağ tarafından kabul edilmeyecektir.</translation> - </message> - <message> - <source>Number of blocks left</source> - <translation>Kalan blokların sayısı</translation> - </message> - <message> <source>Unknown...</source> - <translation>Bilinmiyor...</translation> - </message> - <message> - <source>Last block time</source> - <translation>Son blok zamanı</translation> - </message> - <message> - <source>Progress</source> - <translation>İlerleme</translation> - </message> - <message> - <source>Progress increase per hour</source> - <translation>Saat başı ilerleme artışı</translation> + <translation>Bilinmeyen</translation> </message> <message> <source>calculating...</source> - <translation>hesaplanıyor...</translation> - </message> - <message> - <source>Estimated time left until synced</source> - <translation>Senkronize edilene kadar kalan tahmini süre</translation> + <translation>Hesaplanıyor</translation> </message> <message> <source>Hide</source> <translation>Gizle</translation> </message> - <message> - <source>Esc</source> - <translation>Esc</translation> - </message> - <message> - <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> - <translation>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</translation> - </message> - <message> - <source>Unknown. Syncing Headers (%1, %2%)...</source> - <translation>Unknown. Syncing Headers (%1, %2%)...</translation> - </message> -</context> + </context> <context> <name>OpenURIDialog</name> - <message> - <source>Open bitcoin URI</source> - <translation>Open bitcoin URI</translation> - </message> - <message> - <source>URI:</source> - <translation>URI:</translation> - </message> -</context> + </context> <context> <name>OpenWalletActivity</name> <message> - <source>Open wallet failed</source> - <translation>Open wallet failed</translation> - </message> - <message> - <source>Open wallet warning</source> - <translation>Open wallet warning</translation> - </message> - <message> <source>default wallet</source> - <translation>varsayılan cüzdan</translation> + <translation>Varsayılan cüzdan</translation> </message> - <message> - <source>Opening Wallet <b>%1</b>...</source> - <translation>Opening Wallet <b>%1</b>...</translation> - </message> -</context> + </context> <context> <name>OptionsDialog</name> <message> <source>Options</source> - <translation>Ayarlar</translation> - </message> - <message> - <source>&Main</source> - <translation>&Ana Menü</translation> - </message> - <message> - <source>Automatically start %1 after logging in to the system.</source> - <translation>Sistemde oturum açıldığında %1 programını otomatik olarak başlat.</translation> - </message> - <message> - <source>&Start %1 on system login</source> - <translation>&Açılışta %1 açılsın</translation> - </message> - <message> - <source>Size of &database cache</source> - <translation>Veritabanı önbelleğinin boyutu</translation> - </message> - <message> - <source>Number of script &verification threads</source> - <translation>İş parçacıklarını &denetleme betiği sayısı</translation> - </message> - <message> - <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> - <translation>Proxy bağlantısı IP adresleri (örneğin 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>Bu şebeke türü yoluyla eşlere bağlanmak için belirtilen varsayılan SOCKS5 vekil sunucusunun kullanılıp kullanılmadığını gösterir.</translation> - </message> - <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Tor gizli servisleri aracılığıyla eşlere ulaşmak için ayrı SOCKS&5 proksi kullanın:</translation> - </message> - <message> - <source>Hide the icon from the system tray.</source> - <translation>Simgeyi sistem tepsisinden gizleyin.</translation> - </message> - <message> - <source>&Hide tray icon</source> - <translation>&Simgeyi gizle</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>Pencere kapatıldığında uygulamadan çıkmak yerine uygulamayı küçültür. Bu seçenek etkinleştirildiğinde, uygulama sadece menüden çıkış seçildiğinde kapanacaktır.</translation> - </message> - <message> - <source>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>İşlemler sekmesinde bağlam menüsü unsurları olarak görünen üçüncü taraf bağlantıları (mesela bir blok tarayıcısı). URL'deki %s, işlem hash değeri ile değiştirilecektir. Birden çok bağlantılar düşey çubuklar | ile ayrılacaktır.</translation> - </message> - <message> - <source>Open the %1 configuration file from the working directory.</source> - <translation>Çalışma dizininden %1 yapılandırma dosyasını aç.</translation> - </message> - <message> - <source>Open Configuration File</source> - <translation>Konfigürasyon dosyasını aç</translation> - </message> - <message> - <source>Reset all client options to default.</source> - <translation>Bütün ayarları varsayılana çevir</translation> - </message> - <message> - <source>&Reset Options</source> - <translation>Seçenekleri &Sıfırla</translation> - </message> - <message> - <source>&Network</source> - <translation>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>Gelişmiş bazı ayarlar devredışı bırakılmış fakat tüm bloklar hala tam olarak doğrulanabilir. Bu ayarları geri almak tüm block zinciri'nin tekrar indirilmesini gerektirir. Mevcut disk kullanımınızda bir miktar artış görülebilir.</translation> - </message> - <message> - <source>Prune &block storage to</source> - <translation>Temizle &block depolamasını</translation> - </message> - <message> - <source>GB</source> - <translation>GB</translation> - </message> - <message> - <source>Reverting this setting requires re-downloading the entire blockchain.</source> - <translation>Bu ayarları geri değiştirmek tüm blok zinciri'nin indirilmesini gerektirir.</translation> - </message> - <message> - <source>MiB</source> - <translation>MiB</translation> - </message> - <message> - <source>(0 = auto, <0 = leave that many cores free)</source> - <translation>(0 = otomatik, <0 = bu kadar çekirdeği kullanma)</translation> - </message> - <message> - <source>W&allet</source> - <translation>Cüzdan</translation> - </message> - <message> - <source>Expert</source> - <translation>Gelişmiş</translation> - </message> - <message> - <source>Enable coin &control features</source> - <translation>Para &kontrolü özelliklerini etkinleştir</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>Doğrulanmamış para üstünü harcamayı devre dışı bırakırsanız, bir işlemin para üstü bu işlem için en az bir doğrulama olana dek harcanamaz. Bu, aynı zamanda bakiyenizin nasıl hesaplandığını da etkiler.</translation> - </message> - <message> - <source>&Spend unconfirmed change</source> - <translation>Doğrulanmamış para üstünü &harca</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>Yönlendiricide Bitcoin istemci portlarını otomatik olarak açar. Bu, sadece yönlendiricinizin UPnP desteği bulunuyorsa ve etkinse çalışabilir.</translation> - </message> - <message> - <source>Map port using &UPnP</source> - <translation>Portları &UPnP kullanarak haritala</translation> - </message> - <message> - <source>Accept connections from outside.</source> - <translation>Dışarıdan bağlantıları kabul et.</translation> - </message> - <message> - <source>Allow incomin&g connections</source> - <translation>Gelen bağlantılara izin ver</translation> - </message> - <message> - <source>Connect to the Bitcoin network through a SOCKS5 proxy.</source> - <translation>Bitcoin ağına bir SOCKS5 vekil sunucusu aracılığıyla bağlan.</translation> - </message> - <message> - <source>&Connect through SOCKS5 proxy (default proxy):</source> - <translation>SOCKS5 vekil sunucusu aracılığıyla &bağlan (varsayılan vekil sunucusu):</translation> + <translation>Seçenekler</translation> </message> <message> <source>Proxy &IP:</source> - <translation>Vekil &IP:</translation> - </message> - <message> - <source>&Port:</source> - <translation>&Port:</translation> - </message> - <message> - <source>Port of the proxy (e.g. 9050)</source> - <translation>Proxy portu (örneğin 9050)</translation> - </message> - <message> - <source>Used for reaching peers via:</source> - <translation>Eşlere ulaşmak için kullanılır, şu üzerinden:</translation> + <translation>Proxy &IP:</translation> </message> <message> <source>IPv4</source> @@ -1267,62 +577,10 @@ <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>Bitcoin ağına gizli Tor servisleri için ayrı bir SOCKS5 vekil sunucusu aracılığıyla bağlan.</translation> - </message> - <message> <source>&Window</source> <translation>Pencere</translation> </message> <message> - <source>Show only a tray icon after minimizing the window.</source> - <translation>Küçültüldükten sonra sadece tepsi simgesi göster.</translation> - </message> - <message> - <source>&Minimize to the tray instead of the taskbar</source> - <translation>İşlem çubuğu yerine sistem çekmecesine &küçült</translation> - </message> - <message> - <source>M&inimize on close</source> - <translation>Kapatma sırasında k&üçült</translation> - </message> - <message> - <source>&Display</source> - <translation>&Görünüm</translation> - </message> - <message> - <source>User Interface &language:</source> - <translation>Kullanıcı arayüzü dili</translation> - </message> - <message> - <source>The user interface language can be set here. This setting will take effect after restarting %1.</source> - <translation>Kullanıcı arayüzünün dili burada belirtilebilir. Bu ayar %1 tekrar başlatıldığında etkinleşecektir.</translation> - </message> - <message> - <source>&Unit to show amounts in:</source> - <translation>Tutarı göstermek için &birim:</translation> - </message> - <message> - <source>Choose the default subdivision unit to show in the interface and when sending coins.</source> - <translation>Bitcoin gönderildiğinde arayüzde gösterilecek varsayılan alt birimi seçiniz.</translation> - </message> - <message> - <source>Whether to show coin control features or not.</source> - <translation>Para kontrol özelliklerinin gösterilip gösterilmeyeceğini ayarlar.</translation> - </message> - <message> - <source>&Third party transaction URLs</source> - <translation>&Üçüncü parti işlem URL'leri</translation> - </message> - <message> - <source>Options set in this dialog are overridden by the command line or in the configuration file:</source> - <translation>Options set in this dialog are overridden by the command line or in the configuration file:</translation> - </message> - <message> <source>&OK</source> <translation>Tamam</translation> </message> @@ -1336,393 +594,84 @@ </message> <message> <source>none</source> - <translation>boş</translation> + <translation>hiçbiri</translation> </message> <message> <source>Confirm options reset</source> - <translation>Seçeneklerin sıfırlanmasını teyit et</translation> - </message> - <message> - <source>Client restart required to activate changes.</source> - <translation>Değişikliklerin aktif edilebilmesi için yeniden başlatma gerekiyor.</translation> - </message> - <message> - <source>Client will be shut down. Do you want to proceed?</source> - <translation>İstemci kapanacaktır. Devam etmek istiyor musunuz?</translation> - </message> - <message> - <source>Configuration options</source> - <translation>Konfigürasyon ayarları</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>Konfigürasyon dosyası GUI ayarlarını geçersiz kılmak için gelişmiş kullanıcı ayarlarını değiştirir. Ek olarak, herhangi bir komut satırı seçeneği konfigürasyon dosyasını geçersiz kılar.</translation> + <translation>Seçenekleri sıfırlamayı onayla</translation> </message> <message> <source>Error</source> <translation>Hata</translation> </message> - <message> - <source>The configuration file could not be opened.</source> - <translation>Konfigürasyon dosyası açılamadı.</translation> - </message> - <message> - <source>This change would require a client restart.</source> - <translation>Bu değişiklik istemcinin yeniden başlatılmasını gerektirir.</translation> - </message> - <message> - <source>The supplied proxy address is invalid.</source> - <translation>Sağlanan proxy adresi geçerli değil.</translation> - </message> -</context> + </context> <context> <name>OverviewPage</name> <message> - <source>Form</source> - <translation>Form</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>Gösterilen bilgi geçerli olmayabilir. Bağlantı tekrar sağlandıktan sonra cüzdanınız otomatik olarak senkronize olacaktır. Henüz senkronize olma işlemi tamamlanmadı.</translation> - </message> - <message> - <source>Watch-only:</source> - <translation>Sadece görüntülenebilir:</translation> - </message> - <message> - <source>Available:</source> - <translation>Kullanılabilir:</translation> - </message> - <message> - <source>Your current spendable balance</source> - <translation>Mevcut harcanabilir tutarınız</translation> - </message> - <message> - <source>Pending:</source> - <translation>Bekleyen:</translation> - </message> - <message> - <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> - <translation>Henüz doğrulanmamış ve harcanabilir bakiyeye eklenmemiş işlemlerin toplamı</translation> - </message> - <message> - <source>Immature:</source> - <translation>Olgunlaşmamış:</translation> - </message> - <message> - <source>Mined balance that has not yet matured</source> - <translation>Oluşturulan bakiye henüz olgunlaşmamıştır</translation> - </message> - <message> <source>Balances</source> - <translation>Bakiyeler</translation> + <translation>Hesaplar</translation> </message> <message> <source>Total:</source> - <translation>Toplam:</translation> - </message> - <message> - <source>Your current total balance</source> - <translation>Toplam mevcut miktarınız</translation> - </message> - <message> - <source>Your current balance in watch-only addresses</source> - <translation>Sadece görüntülenebilir adreslerdeki mevcut miktarınız</translation> + <translation>Toplam</translation> </message> <message> <source>Spendable:</source> - <translation>Harcanabilir:</translation> + <translation>Harcanabilir</translation> </message> <message> <source>Recent transactions</source> - <translation>Yakın zamanda yapılmış işlemler</translation> - </message> - <message> - <source>Unconfirmed transactions to watch-only addresses</source> - <translation>Sadece görüntülenebilir adreslerdeki doğrulanmamış işlemler</translation> + <translation>Yakın zamandaki işlemler</translation> </message> + </context> +<context> + <name>PSBTOperationsDialog</name> <message> - <source>Mined balance in watch-only addresses that has not yet matured</source> - <translation>Sadece izlenen adreslerin henüz olgunlaşmamış oluşturulan bakiyeleri</translation> + <source>Dialog</source> + <translation>Diyalog</translation> </message> <message> - <source>Current total balance in watch-only addresses</source> - <translation>Sadece görüntülenebilir adreslerdeki mevcut toplam miktar</translation> + <source>or</source> + <translation>veya</translation> </message> -</context> + </context> <context> <name>PaymentServer</name> <message> <source>Payment request error</source> <translation>Ödeme isteği hatası</translation> </message> - <message> - <source>Cannot start bitcoin: click-to-pay handler</source> - <translation>Bitcoin başlatılamadı: tıkla-ve-öde yöneticisi</translation> - </message> - <message> - <source>URI handling</source> - <translation>URI yönetimi</translation> - </message> - <message> - <source>'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> - <translation>'bitcoin://' geçerli bir protokol değil. Onun yerine 'bitcoin:' kullanınız.</translation> - </message> - <message> - <source>Cannot process payment request because BIP70 is not supported.</source> - <translation>Cannot process payment request because BIP70 is not supported.</translation> - </message> - <message> - <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> - <translation>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</translation> - </message> - <message> - <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> - <translation>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</translation> - </message> - <message> - <source>Invalid payment address %1</source> - <translation>Hatalı ödeme adresi %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 ayrıştırılamıyor! Bunun nedeni geçersiz bir Bitcoin adresi veya hatalı biçimlendirilmiş URI değişkenleri olabilir.</translation> - </message> - <message> - <source>Payment request file handling</source> - <translation>Ödeme talebi dosyası yönetimi</translation> - </message> -</context> + </context> <context> <name>PeerTableModel</name> <message> - <source>User Agent</source> - <translation>Kullanıcı Yazılımı</translation> - </message> - <message> - <source>Node/Service</source> - <translation>Düğüm/Servis</translation> - </message> - <message> - <source>NodeId</source> - <translation>Düğüm ID'si</translation> - </message> - <message> - <source>Ping</source> - <translation>Ping</translation> - </message> - <message> <source>Sent</source> - <translation>Gönder</translation> + <translation>Gönderildi</translation> </message> - <message> - <source>Received</source> - <translation>Alındı</translation> - </message> -</context> + </context> <context> <name>QObject</name> <message> <source>Amount</source> - <translation>Tutar</translation> - </message> - <message> - <source>Enter a Bitcoin address (e.g. %1)</source> - <translation>Bitcoin adresinizi girin (örneğin %1)</translation> - </message> - <message> - <source>%1 d</source> - <translation>%1 g</translation> - </message> - <message> - <source>%1 h</source> - <translation>%1 s</translation> - </message> - <message> - <source>%1 m</source> - <translation>%1 d</translation> - </message> - <message> - <source>%1 s</source> - <translation>%1 s</translation> - </message> - <message> - <source>None</source> - <translation>Boş</translation> - </message> - <message> - <source>N/A</source> - <translation>Yok</translation> - </message> - <message> - <source>%1 ms</source> - <translation>%1 ms</translation> - </message> - <message numerus="yes"> - <source>%n second(s)</source> - <translation><numerusform>%n saniye</numerusform><numerusform>%n saniye</numerusform></translation> - </message> - <message numerus="yes"> - <source>%n minute(s)</source> - <translation><numerusform>%n dakika</numerusform><numerusform>%n dakika</numerusform></translation> - </message> - <message numerus="yes"> - <source>%n hour(s)</source> - <translation><numerusform>%n saat</numerusform><numerusform>%n saat</numerusform></translation> - </message> - <message numerus="yes"> - <source>%n day(s)</source> - <translation><numerusform>%n gün</numerusform><numerusform>%n gün</numerusform></translation> - </message> - <message numerus="yes"> - <source>%n week(s)</source> - <translation><numerusform>%n hafta</numerusform><numerusform>%n hafta</numerusform></translation> - </message> - <message> - <source>%1 and %2</source> - <translation>%1 ve %2</translation> - </message> - <message numerus="yes"> - <source>%n year(s)</source> - <translation><numerusform>%n yıl</numerusform><numerusform>%n yıl</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>Error: Specified data directory "%1" does not exist.</source> - <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> - <message> - <source>%1 didn't yet exit safely...</source> - <translation>%1 henüz güvenli bir şekilde çıkış yapmamıştır...</translation> + <translation>Mitar</translation> </message> <message> <source>unknown</source> - <translation>bilinmiyor</translation> + <translation>bilinmeyen</translation> </message> </context> <context> <name>QRImageWidget</name> <message> - <source>&Save Image...</source> - <translation>&Görüntüyü kaydet</translation> - </message> - <message> - <source>&Copy Image</source> - <translation>&Görüntüyü kopyala</translation> - </message> - <message> - <source>Resulting URI too long, try to reduce the text for label / message.</source> - <translation>Sonuç URI çok uzun, etiket ya da ileti metnini kısaltmayı deneyiniz.</translation> - </message> - <message> - <source>Error encoding URI into QR Code.</source> - <translation>URI'nin QR koduna kodlanmasında hata oluştu.</translation> - </message> - <message> - <source>QR code support not available.</source> - <translation>QR code support not available.</translation> - </message> - <message> <source>Save QR Code</source> <translation>QR kodu kaydet</translation> </message> - <message> - <source>PNG Image (*.png)</source> - <translation>PNG Resim (*.png)</translation> - </message> -</context> + </context> <context> <name>RPCConsole</name> <message> - <source>N/A</source> - <translation>Yok</translation> - </message> - <message> - <source>Client version</source> - <translation>Arayüz versiyonu</translation> - </message> - <message> - <source>&Information</source> - <translation>&Bilgi</translation> - </message> - <message> - <source>General</source> - <translation>Genel</translation> - </message> - <message> - <source>Using BerkeleyDB version</source> - <translation>Kullanılan BerkeleyDB versiyonu</translation> - </message> - <message> - <source>Datadir</source> - <translation>Veri konumu</translation> - </message> - <message> - <source>To specify a non-default location of the data directory use the '%1' option.</source> - <translation>To specify a non-default location of the data directory use the '%1' option.</translation> - </message> - <message> - <source>Blocksdir</source> - <translation>Blocksdir</translation> - </message> - <message> - <source>To specify a non-default location of the blocks directory use the '%1' option.</source> - <translation>To specify a non-default location of the blocks directory use the '%1' option.</translation> - </message> - <message> - <source>Startup time</source> - <translation>Başlangıç zamanı</translation> - </message> - <message> - <source>Network</source> - <translation>Ağ</translation> - </message> - <message> <source>Name</source> - <translation>İsim</translation> - </message> - <message> - <source>Number of connections</source> - <translation>Bağlantı sayısı</translation> - </message> - <message> - <source>Block chain</source> - <translation>Blok zinciri</translation> - </message> - <message> - <source>Current number of blocks</source> - <translation>Güncel blok sayısı</translation> - </message> - <message> - <source>Memory Pool</source> - <translation>Bellek Alanı</translation> - </message> - <message> - <source>Current number of transactions</source> - <translation>Güncel işlem sayısı</translation> + <translation>isim</translation> </message> <message> <source>Memory usage</source> @@ -1730,395 +679,63 @@ </message> <message> <source>Wallet: </source> - <translation>Cüzdan:</translation> - </message> - <message> - <source>(none)</source> - <translation>(boş)</translation> - </message> - <message> - <source>&Reset</source> - <translation>&Yeniden başlat</translation> - </message> - <message> - <source>Received</source> - <translation>Alındı</translation> + <translation>Cüzdan</translation> </message> <message> <source>Sent</source> - <translation>Gönder</translation> - </message> - <message> - <source>&Peers</source> - <translation>&Eşler</translation> - </message> - <message> - <source>Banned peers</source> - <translation>Yasaklı eşler</translation> - </message> - <message> - <source>Select a peer to view detailed information.</source> - <translation>Ayrıntılı bilgi görmek için bir eş seçin.</translation> - </message> - <message> - <source>Whitelisted</source> - <translation>Beyaz listede</translation> - </message> - <message> - <source>Direction</source> - <translation>Yön</translation> + <translation>Gönderildi</translation> </message> <message> <source>Version</source> <translation>Versiyon</translation> </message> <message> - <source>Starting Block</source> - <translation>Başlangıç Bloku</translation> - </message> - <message> - <source>Synced Headers</source> - <translation>Eşleşmiş Üstbilgiler</translation> - </message> - <message> - <source>Synced Blocks</source> - <translation>Eşleşmiş Bloklar</translation> - </message> - <message> - <source>User Agent</source> - <translation>Kullanıcı Yazılımı</translation> - </message> - <message> - <source>Node window</source> - <translation>Node window</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>Güncel veri klasöründen %1 hata ayıklama kütük dosyasını açar. Büyük kütük dosyaları için bu birkaç saniye alabilir.</translation> - </message> - <message> - <source>Decrease font size</source> - <translation>Font boyutunu küçült</translation> - </message> - <message> - <source>Increase font size</source> - <translation>Yazıtipi boyutunu büyült</translation> - </message> - <message> <source>Services</source> <translation>Servisler</translation> </message> <message> - <source>Ban Score</source> - <translation>Yasaklama Skoru</translation> - </message> - <message> - <source>Connection Time</source> - <translation>Bağlantı süresi</translation> - </message> - <message> - <source>Last Send</source> - <translation>Son gönderim</translation> - </message> - <message> - <source>Last Receive</source> - <translation>Son alış</translation> - </message> - <message> - <source>Ping Time</source> - <translation>Ping süresi</translation> - </message> - <message> - <source>The duration of a currently outstanding ping.</source> - <translation>Güncel olarak göze çarpan bir ping'in süresi.</translation> - </message> - <message> - <source>Ping Wait</source> - <translation>Ping bekliyor</translation> - </message> - <message> - <source>Min Ping</source> - <translation>En Düşük Ping</translation> - </message> - <message> - <source>Time Offset</source> - <translation>Saat Farkı</translation> - </message> - <message> - <source>Last block time</source> - <translation>Son blok zamanı</translation> - </message> - <message> - <source>&Open</source> - <translation>&Aç</translation> - </message> - <message> - <source>&Console</source> - <translation>&Konsol</translation> - </message> - <message> - <source>&Network Traffic</source> - <translation>&Ağ trafiği</translation> - </message> - <message> - <source>Totals</source> - <translation>Toplam</translation> - </message> - <message> - <source>In:</source> - <translation>İçeri:</translation> - </message> - <message> - <source>Out:</source> - <translation>Dışarı:</translation> - </message> - <message> - <source>Debug log file</source> - <translation>Hata ayıklama kütük dosyası</translation> - </message> - <message> - <source>Clear console</source> - <translation>Konsolu temizle</translation> - </message> - <message> - <source>1 &hour</source> - <translation>1 &saat</translation> - </message> - <message> - <source>1 &day</source> - <translation>1 &gün</translation> - </message> - <message> - <source>1 &week</source> - <translation>1 &hafta</translation> - </message> - <message> - <source>1 &year</source> - <translation>1 &yıl</translation> - </message> - <message> - <source>&Disconnect</source> - <translation>&Bağlantı kesildi</translation> - </message> - <message> - <source>Ban for</source> - <translation>Yasakla</translation> - </message> - <message> - <source>&Unban</source> - <translation>&Yasaklamayı Kaldır</translation> - </message> - <message> - <source>Welcome to the %1 RPC console.</source> - <translation>%1 RPC konsoluna hoş geldiniz.</translation> - </message> - <message> - <source>Use up and down arrows to navigate history, and %1 to clear screen.</source> - <translation>Geçmişte gezinmek için yukarı ve aşağı oklarını kullanın ve ekranı temizlemek için %1 kullanın.</translation> - </message> - <message> - <source>Type %1 for an overview of available commands.</source> - <translation>Mevcut komutlara göz atmak için %1 yazın.</translation> - </message> - <message> - <source>For more information on using this console type %1.</source> - <translation>Bu konsolun kullanımı hakkında daha fazla bilgi için %1 yazın.</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>UYARI: Bitcoin dolandırıcılarının çok fazla etkin olduğu zamanlarda, dolandırıcılar bazı kullanıcılara buraya komutlar yazmalarını söylerek onların cüzdanlarındaki bitcoinleri çalmışlardır. Bir komutun sonuçlarını tam olarak anlamadan bu konsolu kullanmayın.</translation> - </message> - <message> - <source>Network activity disabled</source> - <translation>Ağ aktivitesi pasif</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> - <message> - <source>via %1</source> - <translation>%1 vasıtasıyla</translation> - </message> - <message> <source>never</source> - <translation>asla</translation> - </message> - <message> - <source>Inbound</source> - <translation>Gelen</translation> - </message> - <message> - <source>Outbound</source> - <translation>Giden</translation> - </message> - <message> - <source>Yes</source> - <translation>Evet</translation> - </message> - <message> - <source>No</source> - <translation>Hayır</translation> + <translation>Hiçbir zaman </translation> </message> <message> <source>Unknown</source> - <translation>Bilinmiyor</translation> + <translation>Bilinmeyen</translation> </message> </context> <context> <name>ReceiveCoinsDialog</name> <message> - <source>&Amount:</source> - <translation>&Tutar:</translation> - </message> - <message> - <source>&Label:</source> - <translation>&Etiket</translation> - </message> - <message> - <source>&Message:</source> - <translation>&Mesaj</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>Talep açıldığında gösterilecek, isteğinize dayalı, ödeme talebi ile ilişkilendirilecek bir ileti. Not: Bu ileti ödeme ile birlikte Bitcoin ağı üzerinden gönderilmeyecektir.</translation> - </message> - <message> - <source>An optional label to associate with the new receiving address.</source> - <translation>Yeni alım adresi ile ilişkili, seçiminize dayalı etiket.</translation> - </message> - <message> - <source>Use this form to request payments. All fields are <b>optional</b>.</source> - <translation>Ödeme talep etmek için bu formu kullanın. Tüm alanlar <b>seçime dayalıdır</b>.</translation> - </message> - <message> - <source>An optional amount to request. Leave this empty or zero to not request a specific amount.</source> - <translation>Seçiminize dayalı talep edilecek tutar. Belli bir tutar talep etmemek için bunu boş bırakın veya sıfır değerini kullanın.</translation> - </message> - <message> - <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> - <translation>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</translation> - </message> - <message> - <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> - <translation>An optional message that is attached to the payment request and may be displayed to the sender.</translation> - </message> - <message> - <source>&Create new receiving address</source> - <translation>&Create new receiving address</translation> - </message> - <message> - <source>Clear all fields of the form.</source> - <translation>Formdaki tüm alanları temizle.</translation> - </message> - <message> - <source>Clear</source> - <translation>Temizle</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>Yerli segwit (Bech32) adresi oluştur</translation> - </message> - <message> - <source>Requested payments history</source> - <translation>Talep edilen ödemelerin tarihçesi</translation> - </message> - <message> - <source>Show the selected request (does the same as double clicking an entry)</source> - <translation>Seçilen talebi göster (bir unsura çift tıklamakla aynı anlama gelir)</translation> - </message> - <message> - <source>Show</source> - <translation>Göster</translation> - </message> - <message> - <source>Remove the selected entries from the list</source> - <translation>Seçilen unsurları listeden kaldır</translation> - </message> - <message> - <source>Remove</source> - <translation>Sil</translation> - </message> - <message> - <source>Copy URI</source> - <translation>URI'yi kopyala</translation> - </message> - <message> <source>Copy label</source> <translation>Etiketi kopyala</translation> </message> <message> - <source>Copy message</source> - <translation>Mesajı kopyala</translation> + <source>Copy amount</source> + <translation>Miktar kopyala</translation> </message> <message> - <source>Copy amount</source> - <translation>Tutarı kopyala</translation> + <source>Could not unlock wallet.</source> + <translation>Cüzdan kilidi açılamadı.</translation> </message> -</context> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR kod</translation> - </message> - <message> - <source>Copy &URI</source> - <translation>URI'yi kopyala</translation> - </message> - <message> - <source>Copy &Address</source> - <translation>&Adresi Kopyala</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>&Görüntüyü kaydet</translation> - </message> - <message> - <source>Request payment to %1</source> - <translation>%1 unsuruna ödeme talep et</translation> - </message> - <message> - <source>Payment information</source> - <translation>Ödeme bilgisi</translation> - </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>adres</translation> - </message> - <message> - <source>Amount</source> - <translation>Tutar</translation> + <source>Amount:</source> + <translation>Tutar:</translation> </message> <message> - <source>Label</source> - <translation>etiket</translation> + <source>Label:</source> + <translation>Etiket:</translation> </message> <message> - <source>Message</source> - <translation>Mesaj</translation> + <source>Message:</source> + <translation>İleti:</translation> </message> <message> - <source>Wallet</source> + <source>Wallet:</source> <translation>Cüzdan</translation> </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -2127,790 +744,82 @@ </message> <message> <source>Label</source> - <translation>etiket</translation> - </message> - <message> - <source>Message</source> - <translation>Mesaj</translation> + <translation>Etiket</translation> </message> <message> <source>(no label)</source> <translation>(etiket yok)</translation> </message> - <message> - <source>(no message)</source> - <translation>(mesaj yok)</translation> - </message> - <message> - <source>(no amount requested)</source> - <translation>(tutar talep edilmedi)</translation> - </message> - <message> - <source>Requested</source> - <translation>Talep edilen</translation> - </message> -</context> + </context> <context> <name>SendCoinsDialog</name> <message> - <source>Send Coins</source> - <translation>Coin gönder</translation> - </message> - <message> - <source>Coin Control Features</source> - <translation>Para kontrolü özellikleri</translation> - </message> - <message> - <source>Inputs...</source> - <translation>Girdiler...</translation> - </message> - <message> - <source>automatically selected</source> - <translation>Otomatik seçildi</translation> - </message> - <message> - <source>Insufficient funds!</source> - <translation>Yetersiz fon!</translation> - </message> - <message> <source>Quantity:</source> - <translation>Miktar:</translation> - </message> - <message> - <source>Bytes:</source> - <translation>Bayt</translation> + <translation>Miktar</translation> </message> <message> <source>Amount:</source> - <translation>Tutar:</translation> + <translation>Miktar</translation> </message> <message> <source>Fee:</source> - <translation>Ücret:</translation> - </message> - <message> - <source>After Fee:</source> - <translation>Ücretten sonra kalan:</translation> + <translation>Ücret</translation> </message> <message> <source>Change:</source> - <translation>Değişen:</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>Bu etkinleştirildiyse fakat para üstü adresi boş ya da geçersizse para üstü yeni oluşturulan bir adrese gönderilecektir.</translation> - </message> - <message> - <source>Custom change address</source> - <translation>Özel para üstü adresi</translation> - </message> - <message> - <source>Transaction Fee:</source> - <translation>Gönderim ücreti:</translation> - </message> - <message> - <source>Choose...</source> - <translation>Seçiniz...</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>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.</translation> - </message> - <message> - <source>Warning: Fee estimation is currently not possible.</source> - <translation>Uyarı: Ücret tahmini şu anda mümkün değildir.</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>kilobyte başına</translation> + <translation>Değiştir</translation> </message> <message> <source>Hide</source> <translation>Gizle</translation> </message> <message> - <source>Recommended:</source> - <translation>Önerilen:</translation> - </message> - <message> - <source>Custom:</source> - <translation>Özel:</translation> - </message> - <message> - <source>(Smart fee not initialized yet. This usually takes a few blocks...)</source> - <translation>(Zeki ücret henüz başlatılmadı. Bu genelde birkaç blok alır...)</translation> - </message> - <message> - <source>Send to multiple recipients at once</source> - <translation>Birçok alıcıya aynı anda gönder</translation> - </message> - <message> - <source>Add &Recipient</source> - <translation>&Alıcı ekle</translation> - </message> - <message> - <source>Clear all fields of the form.</source> - <translation>Formdaki tüm alanları temizle.</translation> - </message> - <message> - <source>Dust:</source> - <translation>Toz:</translation> - </message> - <message> - <source>Hide transaction fee settings</source> - <translation>Hide transaction fee settings</translation> - </message> - <message> - <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> - <translation>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.</translation> - </message> - <message> - <source>A too low fee might result in a never confirming transaction (read the tooltip)</source> - <translation>A too low fee might result in a never confirming transaction (read the tooltip)</translation> - </message> - <message> - <source>Confirmation time target:</source> - <translation>Doğrulama süresi hedefi:</translation> - </message> - <message> - <source>Enable Replace-By-Fee</source> - <translation>Enable 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>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.</translation> - </message> - <message> - <source>Clear &All</source> - <translation>Hepsini sil</translation> - </message> - <message> - <source>Balance:</source> - <translation>Bakiye:</translation> - </message> - <message> - <source>Confirm the send action</source> - <translation>Yollama etkinliğini teyit ediniz</translation> - </message> - <message> - <source>S&end</source> - <translation>G&önder</translation> - </message> - <message> <source>Copy quantity</source> <translation>Miktarı kopyala</translation> </message> <message> <source>Copy amount</source> - <translation>Tutarı kopyala</translation> + <translation>Miktar kopyala</translation> </message> <message> <source>Copy fee</source> <translation>Ücreti kopyala</translation> </message> <message> - <source>Copy after fee</source> - <translation>Ücretten sonrasını kopyala</translation> - </message> - <message> - <source>Copy bytes</source> - <translation>Baytları kopyala</translation> - </message> - <message> - <source>Copy dust</source> - <translation>Tozu kopyala</translation> - </message> - <message> - <source>Copy change</source> - <translation>Para üstünü kopyala</translation> - </message> - <message> - <source>%1 (%2 blocks)</source> - <translation>%1 (%2 blok)</translation> - </message> - <message> - <source>Cr&eate Unsigned</source> - <translation>Cr&eate Unsigned</translation> - </message> - <message> - <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> - </message> - <message> - <source> from wallet '%1'</source> - <translation> from wallet '%1'</translation> - </message> - <message> - <source>%1 to '%2'</source> - <translation>%1 to '%2'</translation> - </message> - <message> - <source>%1 to %2</source> - <translation>%1'den %2'e</translation> - </message> - <message> - <source>Do you want to draft this transaction?</source> - <translation>Do you want to draft this transaction?</translation> - </message> - <message> - <source>Are you sure you want to send?</source> - <translation>Göndermek istediğinize emin misiniz?</translation> - </message> - <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</translation> - </message> - <message> - <source>or</source> - <translation>ya da</translation> - </message> - <message> - <source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> - <translation>You can increase the fee later (signals Replace-By-Fee, BIP-125).</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>Gönderim ücreti</translation> - </message> - <message> - <source>Not signalling Replace-By-Fee, BIP-125.</source> - <translation>Not signalling Replace-By-Fee, BIP-125.</translation> - </message> - <message> - <source>Total Amount</source> - <translation>Toplam Tutar</translation> - </message> - <message> - <source>To review recipient list click "Show Details..."</source> - <translation>To review recipient list click "Show Details..."</translation> - </message> - <message> - <source>Confirm send coins</source> - <translation>Coin gönderimini onaylayın</translation> - </message> - <message> - <source>Confirm transaction proposal</source> - <translation>Confirm transaction proposal</translation> - </message> - <message> - <source>Copy PSBT to clipboard</source> - <translation>Copy PSBT to clipboard</translation> - </message> - <message> - <source>Send</source> - <translation>Send</translation> - </message> - <message> - <source>PSBT copied</source> - <translation>PSBT copied</translation> - </message> - <message> - <source>Watch-only balance:</source> - <translation>Watch-only balance:</translation> - </message> - <message> - <source>The recipient address is not valid. Please recheck.</source> - <translation>Alıcı adresi geçerli değildir. Lütfen tekrar kontrol ediniz.</translation> - </message> - <message> - <source>The amount to pay must be larger than 0.</source> - <translation>Ödeyeceğiniz tutarın 0'dan yüksek olması gerekir.</translation> - </message> - <message> - <source>The amount exceeds your balance.</source> - <translation>Tutar bakiyenizden yüksektir.</translation> - </message> - <message> - <source>The total exceeds your balance when the %1 transaction fee is included.</source> - <translation>Toplam, %1 işlem ücreti eklendiğinde bakiyenizi geçmektedir.</translation> - </message> - <message> - <source>Duplicate address found: addresses should only be used once each.</source> - <translation>Tekrarlayan adres bulundu: adresler sadece bir kez kullanılmalıdır.</translation> - </message> - <message> - <source>Transaction creation failed!</source> - <translation>İşlem oluşturma başarısız!</translation> - </message> - <message> - <source>A fee higher than %1 is considered an absurdly high fee.</source> - <translation>%1 tutarından yüksek bir ücret saçma derecede yüksek bir ücret olarak kabul edilir.</translation> - </message> - <message> - <source>Payment request expired.</source> - <translation>Ödeme talebinin geçerlilik süresi bitti.</translation> - </message> - <message numerus="yes"> - <source>Estimated to begin confirmation within %n block(s).</source> - <translation><numerusform>Tahmini %n blok içinde doğrulamaya başlanacaktır.</numerusform><numerusform>Tahmini %n blok içinde doğrulamaya başlanacaktır.</numerusform></translation> - </message> - <message> - <source>Warning: Invalid Bitcoin address</source> - <translation>Uyarı: Hatalı Bitcoin adresi</translation> - </message> - <message> - <source>Warning: Unknown change address</source> - <translation>Uyarı: Bilinmeyen para üstü adresi</translation> - </message> - <message> - <source>Confirm custom change address</source> - <translation>Özel para üstü adresini onayla</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>Para üstü için seçtiğiniz adres bu cüzdanın bir parçası değil. Cüzdanınızdaki bir miktar veya tüm para bu adrese gönderilebilir. Emin misiniz?</translation> - </message> - <message> <source>(no label)</source> <translation>(etiket yok)</translation> </message> </context> <context> <name>SendCoinsEntry</name> - <message> - <source>A&mount:</source> - <translation>T&utar:</translation> - </message> - <message> - <source>Pay &To:</source> - <translation>&Şu adrese öde:</translation> - </message> - <message> - <source>&Label:</source> - <translation>&Etiket</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation>Önceden kullanılmış adres seç</translation> - </message> - <message> - <source>The Bitcoin address to send the payment to</source> - <translation>Ödemenin yollanacağı Bitcoin adresi</translation> - </message> - <message> - <source>Alt+A</source> - <translation>Alt+A</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation>Panodaki adresi yapıştırın</translation> - </message> - <message> - <source>Alt+P</source> - <translation>Alt+P</translation> - </message> - <message> - <source>Remove this entry</source> - <translation>Bu ögeyi kaldır</translation> - </message> - <message> - <source>The amount to send in the selected unit</source> - <translation>The amount to send in the selected unit</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>Ücret yollanan tutardan alınacaktır. Alıcı tutar alanına girdiğinizden daha az bitcoin alacaktır. Eğer birden çok alıcı seçiliyse ücret eşit olarak bölünecektir.</translation> - </message> - <message> - <source>S&ubtract fee from amount</source> - <translation>Ücreti tutardan düş</translation> - </message> - <message> - <source>Use available balance</source> - <translation>Mevcut bakiyeyi kullan</translation> - </message> - <message> - <source>Message:</source> - <translation>Mesaj:</translation> - </message> - <message> - <source>This is an unauthenticated payment request.</source> - <translation>Bu, kimliği doğrulanmamış bir ödeme talebidir.</translation> - </message> - <message> - <source>This is an authenticated payment request.</source> - <translation>Bu, kimliği doğrulanmış bir ödeme talebidir.</translation> - </message> - <message> - <source>Enter a label for this address to add it to the list of used addresses</source> - <translation>Kullanılmış adres listesine eklemek için bu adrese bir etiket girin</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>Referans için bitcoin: URI'siyle iliştirilmiş işlemle birlikte depolanacak bir ileti. Not: Bu mesaj Bitcoin ağı üzerinden gönderilmeyecektir.</translation> - </message> - <message> - <source>Pay To:</source> - <translation>Şu adrese öde:</translation> - </message> - <message> - <source>Memo:</source> - <translation>Not:</translation> - </message> -</context> + </context> <context> <name>ShutdownWindow</name> - <message> - <source>%1 is shutting down...</source> - <translation>%1 kapanıyor...</translation> - </message> - <message> - <source>Do not shut down the computer until this window disappears.</source> - <translation>Bu pencere kalkıncaya dek bilgisayarı kapatmayınız.</translation> - </message> -</context> + </context> <context> <name>SignVerifyMessageDialog</name> - <message> - <source>Signatures - Sign / Verify a Message</source> - <translation>İmzalar - İleti İmzala / Kontrol et</translation> - </message> - <message> - <source>&Sign Message</source> - <translation>İleti &imzala</translation> - </message> - <message> - <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source> - <translation>Adreslerinize yollanan bitcoinleri alabileceğiniz ispatlamak için adreslerinizle iletiler/anlaşmalar imzalayabilirsiniz. Oltalama saldırılarının kimliğinizi imzanızla elde etmeyi deneyebilecekleri için belirsiz ya da rastgele hiçbir şey imzalamamaya dikkat ediniz. Sadece ayrıntılı açıklaması olan ve tümüne katıldığınız ifadeleri imzalayınız.</translation> - </message> - <message> - <source>The Bitcoin address to sign the message with</source> - <translation>İletinin imzalanmasında kullanılacak Bitcoin adresi</translation> - </message> - <message> - <source>Choose previously used address</source> - <translation>Önceden kullanılmış adres seç</translation> - </message> - <message> - <source>Alt+A</source> - <translation>Alt+A</translation> - </message> - <message> - <source>Paste address from clipboard</source> - <translation>Panodaki adresi yapıştırın</translation> - </message> - <message> - <source>Alt+P</source> - <translation>Alt+P</translation> - </message> - <message> - <source>Enter the message you want to sign here</source> - <translation>İmzalamak istediğiniz iletiyi burada giriniz</translation> - </message> - <message> - <source>Signature</source> - <translation>İmza</translation> - </message> - <message> - <source>Copy the current signature to the system clipboard</source> - <translation>Güncel imzayı sistem panosuna kopyala</translation> - </message> - <message> - <source>Sign the message to prove you own this Bitcoin address</source> - <translation>Bu Bitcoin adresinin sizin olduğunu ispatlamak için iletiyi imzalayın</translation> - </message> - <message> - <source>Sign &Message</source> - <translation>İmza &Mesaj</translation> - </message> - <message> - <source>Reset all sign message fields</source> - <translation>Tüm ileti alanlarını sıfırla</translation> - </message> - <message> - <source>Clear &All</source> - <translation>Hepsini sil</translation> - </message> - <message> - <source>&Verify Message</source> - <translation>İletiyi &kontrol et</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>Alıcının adresini, iletiyi (satır sonları, boşluklar, sekmeler vs. karakterleri tam olarak kopyaladığınızdan emin olunuz) ve imzayı aşağıya giriniz. Bir ortadaki adam saldırısı tarafından kandırılmaya engel olmak için imzadan, imzalı iletinin içeriğini aşan bir anlam çıkarmamaya dikkat ediniz. Bunun sadece imzalayan tarafın adres ile alım yapabildiğini ispatladığını ve herhangi bir işlemin gönderi tarafını kanıtlayamayacağını unutmayınız!</translation> - </message> - <message> - <source>The Bitcoin address the message was signed with</source> - <translation>İletinin imzalanmasında kullanılan Bitcoin adresi</translation> - </message> - <message> - <source>The signed message to verify</source> - <translation>The signed message to verify</translation> - </message> - <message> - <source>The signature given when the message was signed</source> - <translation>The signature given when the message was signed</translation> - </message> - <message> - <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation>Belirtilen Bitcoin adresi ile imzalandığını doğrulamak için iletiyi kontrol et</translation> - </message> - <message> - <source>Verify &Message</source> - <translation>&İletiyi kontrol et</translation> - </message> - <message> - <source>Reset all verify message fields</source> - <translation>Tüm ileti kontrolü alanlarını sıfırla</translation> - </message> - <message> - <source>Click "Sign Message" to generate signature</source> - <translation>İmzayı oluşturmak için "İletiyi İmzala"ya tıklayın</translation> - </message> - <message> - <source>The entered address is invalid.</source> - <translation>Girilen adres hatalı.</translation> - </message> - <message> - <source>Please check the address and try again.</source> - <translation>Adresi kontrol ettikten sonra lütfen tekrar deneyin.</translation> - </message> - <message> - <source>The entered address does not refer to a key.</source> - <translation>Girilen adres herhangi bir anahtara işaret etmemektedir.</translation> - </message> - <message> - <source>Wallet unlock was cancelled.</source> - <translation>Cüzdan kilidinin açılması iptal edildi.</translation> - </message> - <message> - <source>No error</source> - <translation>No error</translation> - </message> - <message> - <source>Private key for the entered address is not available.</source> - <translation>Girilen adres için özel anahtar mevcut değildir.</translation> - </message> - <message> - <source>Message signing failed.</source> - <translation>İleti imzalaması başarısız oldu.</translation> - </message> - <message> - <source>Message signed.</source> - <translation>İleti imzalandı.</translation> - </message> - <message> - <source>The signature could not be decoded.</source> - <translation>İmzanın kodu çözülemedi.</translation> - </message> - <message> - <source>Please check the signature and try again.</source> - <translation>İmzanızı kontrol ettikten sonra lütfen tekrar deneyin.</translation> - </message> - <message> - <source>The signature did not match the message digest.</source> - <translation>İmza iletinin özeti ile eşleşmedi.</translation> - </message> - <message> - <source>Message verification failed.</source> - <translation>Mesaj onayı hatalı.</translation> - </message> - <message> - <source>Message verified.</source> - <translation>Mesaj onaylandı.</translation> - </message> -</context> + </context> <context> <name>TrafficGraphWidget</name> - <message> - <source>KB/s</source> - <translation>KB/s</translation> - </message> -</context> + </context> <context> <name>TransactionDesc</name> - <message numerus="yes"> - <source>Open for %n more block(s)</source> - <translation><numerusform>%n taneden daha fazla blok için açık</numerusform><numerusform>%n taneden daha fazla blok için açık</numerusform></translation> - </message> - <message> - <source>Open until %1</source> - <translation>%1 değerine dek açık</translation> - </message> - <message> - <source>conflicted with a transaction with %1 confirmations</source> - <translation>%1 doğrulamalı bir işlem ile çelişti</translation> - </message> - <message> - <source>0/unconfirmed, %1</source> - <translation>0/doğrulanmamış, %1</translation> - </message> - <message> - <source>in memory pool</source> - <translation>bellek alanında</translation> - </message> - <message> - <source>not in memory pool</source> - <translation>bellek alanında değil</translation> - </message> - <message> - <source>abandoned</source> - <translation>terk edilmiş</translation> - </message> - <message> - <source>%1/unconfirmed</source> - <translation>%1/doğrulanmadı</translation> - </message> - <message> - <source>%1 confirmations</source> - <translation>%1 doğrulama</translation> - </message> - <message> - <source>Status</source> - <translation>Durum</translation> - </message> <message> <source>Date</source> <translation>Tarih</translation> </message> <message> - <source>Source</source> - <translation>Kaynak</translation> - </message> - <message> - <source>Generated</source> - <translation>Oluşturuldu</translation> - </message> - <message> - <source>From</source> - <translation>Gönderen</translation> - </message> - <message> <source>unknown</source> - <translation>bilinmiyor</translation> - </message> - <message> - <source>To</source> - <translation>Alıcı</translation> - </message> - <message> - <source>own address</source> - <translation>kendi adresiniz</translation> - </message> - <message> - <source>watch-only</source> - <translation>sadece-izlenen</translation> - </message> - <message> - <source>label</source> - <translation>etiket</translation> - </message> - <message> - <source>Credit</source> - <translation>Alınan Tutar</translation> - </message> - <message numerus="yes"> - <source>matures in %n more block(s)</source> - <translation><numerusform>%n ek blok sonrasında olgunlaşacak</numerusform><numerusform>%n ek blok sonrasında olgunlaşacak</numerusform></translation> - </message> - <message> - <source>not accepted</source> - <translation>kabul edilmedi</translation> - </message> - <message> - <source>Debit</source> - <translation>Çekilen Tutar</translation> - </message> - <message> - <source>Total debit</source> - <translation>Toplam çekilen tutar</translation> - </message> - <message> - <source>Total credit</source> - <translation>Toplam alınan tutar</translation> - </message> - <message> - <source>Transaction fee</source> - <translation>Gönderim ücreti</translation> - </message> - <message> - <source>Net amount</source> - <translation>Net tutar</translation> - </message> - <message> - <source>Message</source> - <translation>Mesaj</translation> - </message> - <message> - <source>Comment</source> - <translation>Yorum</translation> - </message> - <message> - <source>Transaction ID</source> - <translation>İşlem ID'si</translation> - </message> - <message> - <source>Transaction total size</source> - <translation>Gönderimin toplam boyutu</translation> - </message> - <message> - <source>Transaction virtual size</source> - <translation>İşlem sanal boyutu</translation> - </message> - <message> - <source>Output index</source> - <translation>Çıktı indeksi</translation> - </message> - <message> - <source> (Certificate was not verified)</source> - <translation> (Certificate was not verified)</translation> - </message> - <message> - <source>Merchant</source> - <translation>Tüccar</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>Oluşturulan bitcoin'lerin harcanabilmelerinden önce %1 blok beklemeleri gerekmektedir. Bu blok, oluşturduğunuzda, blok zincirine eklenmesi için ağda yayınlandı. Zincire eklenmesi başarısız olursa, durumu "kabul edilmedi" olarak değiştirilecek ve harcanamayacaktır. Bu, bazen başka bir düğüm sizden birkaç saniye önce ya da sonra blok oluşturursa meydana gelebilir.</translation> - </message> - <message> - <source>Debug information</source> - <translation>Hata giderme bilgisi</translation> - </message> - <message> - <source>Transaction</source> - <translation>İşlem</translation> - </message> - <message> - <source>Inputs</source> - <translation>Girdiler</translation> + <translation>bilinmeyen</translation> </message> <message> <source>Amount</source> - <translation>Tutar</translation> - </message> - <message> - <source>true</source> - <translation>doğru</translation> + <translation>Mitar</translation> </message> - <message> - <source>false</source> - <translation>anlış</translation> - </message> -</context> + </context> <context> <name>TransactionDescDialog</name> - <message> - <source>This pane shows a detailed description of the transaction</source> - <translation>Bu pano işlemin ayrıntılı açıklamasını gösterir</translation> - </message> - <message> - <source>Details for %1</source> - <translation>%1 için ayrıntılar</translation> - </message> -</context> + </context> <context> <name>TransactionTableModel</name> <message> @@ -2918,173 +827,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Tarih</translation> </message> <message> - <source>Type</source> - <translation>Tip</translation> - </message> - <message> <source>Label</source> - <translation>etiket</translation> - </message> - <message numerus="yes"> - <source>Open for %n more block(s)</source> - <translation><numerusform>%n taneden daha fazla blok için açık</numerusform><numerusform>%n taneden daha fazla blok için açık</numerusform></translation> - </message> - <message> - <source>Open until %1</source> - <translation>%1 değerine dek açık</translation> - </message> - <message> - <source>Unconfirmed</source> - <translation>Doğrulanmamış</translation> - </message> - <message> - <source>Abandoned</source> - <translation>Terk edilmiş</translation> - </message> - <message> - <source>Confirming (%1 of %2 recommended confirmations)</source> - <translation>Doğrulanıyor (%1 kere doğrulandı, önerilen doğrulama sayısı %2)</translation> - </message> - <message> - <source>Confirmed (%1 confirmations)</source> - <translation>Onaylandı (%1 onaylanan)</translation> - </message> - <message> - <source>Conflicted</source> - <translation>Uyuşmadı</translation> - </message> - <message> - <source>Immature (%1 confirmations, will be available after %2)</source> - <translation>Olgunlaşmamış (%1 doğrulama, %2 doğrulama sonra kullanılabilir olacaktır)</translation> - </message> - <message> - <source>Generated but not accepted</source> - <translation>Oluşturuldu fakat kabul edilmedi</translation> - </message> - <message> - <source>Received with</source> - <translation>ile alındı</translation> - </message> - <message> - <source>Received from</source> - <translation>Alındığı kişi</translation> - </message> - <message> - <source>Sent to</source> - <translation>Gönderildiği adres</translation> - </message> - <message> - <source>Payment to yourself</source> - <translation>Kendinize ödeme</translation> - </message> - <message> - <source>Mined</source> - <translation>Kazıldı</translation> - </message> - <message> - <source>watch-only</source> - <translation>sadece-izlenen</translation> - </message> - <message> - <source>(n/a)</source> - <translation>(yok)</translation> + <translation>Etiket</translation> </message> <message> <source>(no label)</source> <translation>(etiket yok)</translation> </message> - <message> - <source>Transaction status. Hover over this field to show number of confirmations.</source> - <translation>İşlem durumu. Doğrulama sayısını görüntülemek için fare imlecini bu alanın üzerinde tutunuz.</translation> - </message> - <message> - <source>Date and time that the transaction was received.</source> - <translation>İşlemin alındığı tarih ve zaman.</translation> - </message> - <message> - <source>Type of transaction.</source> - <translation>İşlemin türü.</translation> - </message> - <message> - <source>Whether or not a watch-only address is involved in this transaction.</source> - <translation>Bu işleme sadece-izlenen bir adresin dahil edilip, edilmediği.</translation> - </message> - <message> - <source>User-defined intent/purpose of the transaction.</source> - <translation>İşlemin kullanıcı tanımlı amacı.</translation> - </message> - <message> - <source>Amount removed from or added to balance.</source> - <translation>Bakiyeden kaldırılan ya da bakiyeye eklenen tutar.</translation> - </message> -</context> + </context> <context> <name>TransactionView</name> <message> - <source>All</source> - <translation>Hepsi</translation> - </message> - <message> - <source>Today</source> - <translation>Bugün</translation> - </message> - <message> - <source>This week</source> - <translation>Bu hafta</translation> - </message> - <message> - <source>This month</source> - <translation>Bu Ay</translation> - </message> - <message> - <source>Last month</source> - <translation>Son ay</translation> - </message> - <message> - <source>This year</source> - <translation>Bu yıl</translation> - </message> - <message> - <source>Range...</source> - <translation>Tarih Aralığı</translation> - </message> - <message> - <source>Received with</source> - <translation>ile alındı</translation> - </message> - <message> - <source>Sent to</source> - <translation>Gönderildiği adres</translation> - </message> - <message> - <source>To yourself</source> - <translation>Kendinize</translation> - </message> - <message> - <source>Mined</source> - <translation>Kazıldı</translation> - </message> - <message> - <source>Other</source> - <translation>Diğerleri</translation> - </message> - <message> - <source>Enter address, transaction id, or label to search</source> - <translation>Aramak için adres, gönderim numarası ya da etiket yazınız</translation> - </message> - <message> - <source>Min amount</source> - <translation>En düşük tutar</translation> - </message> - <message> - <source>Abandon transaction</source> - <translation>İşlemden vazgeç</translation> - </message> - <message> - <source>Increase transaction fee</source> - <translation>İşlem ücretini artır</translation> - </message> - <message> <source>Copy address</source> <translation>Adresi kopyala</translation> </message> @@ -3094,716 +847,73 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Copy amount</source> - <translation>Tutarı kopyala</translation> + <translation>Miktar kopyala</translation> </message> <message> <source>Copy transaction ID</source> - <translation>İşlem ID'sini kopyala</translation> - </message> - <message> - <source>Copy raw transaction</source> - <translation>Ham işlemi kopyala</translation> - </message> - <message> - <source>Copy full transaction details</source> - <translation>Tüm işlem ayrıntılarını kopyala</translation> - </message> - <message> - <source>Edit label</source> - <translation>Etiketi düzenle</translation> - </message> - <message> - <source>Show transaction details</source> - <translation>İşlem ayrıntılarını göster</translation> - </message> - <message> - <source>Export Transaction History</source> - <translation>İşlem Tarihçesini Dışarı Aktar</translation> + <translation>İşlem numarasını kopyala</translation> </message> <message> <source>Comma separated file (*.csv)</source> - <translation>Virgül ile ayrılmış dosya (*.csv)</translation> - </message> - <message> - <source>Confirmed</source> - <translation>Kabul edilen</translation> - </message> - <message> - <source>Watch-only</source> - <translation>Sadece izlenen</translation> + <translation>Virgülle ayrılmış dosya (*.csv)</translation> </message> <message> <source>Date</source> <translation>Tarih</translation> </message> <message> - <source>Type</source> - <translation>Tip</translation> - </message> - <message> <source>Label</source> - <translation>etiket</translation> + <translation>Etiket</translation> </message> <message> <source>Address</source> - <translation>adres</translation> - </message> - <message> - <source>ID</source> - <translation>ID</translation> + <translation>ADres</translation> </message> <message> <source>Exporting Failed</source> - <translation>Dışa Aktarma Başarısız</translation> - </message> - <message> - <source>There was an error trying to save the transaction history to %1.</source> - <translation>İşlem tarihçesinin %1 konumuna kaydedilmeye çalışıldığı sırada bir hata meydana geldi.</translation> - </message> - <message> - <source>Exporting Successful</source> - <translation>Dışarı Aktarma Başarılı</translation> - </message> - <message> - <source>The transaction history was successfully saved to %1.</source> - <translation>İşlem tarihçesi %1 konumuna başarıyla kaydedildi.</translation> - </message> - <message> - <source>Range:</source> - <translation>Tarih Aralığı:</translation> + <translation>Dışa Aktarım Başarısız Oldu</translation> </message> - <message> - <source>to</source> - <translation>Alıcı</translation> - </message> -</context> + </context> <context> <name>UnitDisplayStatusBarControl</name> - <message> - <source>Unit to show amounts in. Click to select another unit.</source> - <translation>Tutarı göstermek için birim. Başka bir birim seçmek için tıklayınız.</translation> - </message> -</context> + </context> <context> <name>WalletController</name> <message> <source>Close wallet</source> - <translation>Cüzdanı Kapat</translation> + <translation>Cüzdan kapat</translation> </message> - <message> - <source>Are you sure you wish to close the wallet <i>%1</i>?</source> - <translation>Are you sure you wish to close the wallet <i>%1</i>?</translation> - </message> - <message> - <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> - <translation>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</translation> - </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Hiçbir cüzdan yüklenmedi.</translation> + <source>Create a new wallet</source> + <translation>Yeni bir cüzdan oluştur</translation> </message> </context> <context> <name>WalletModel</name> <message> - <source>Send Coins</source> - <translation>Coin gönder</translation> - </message> - <message> - <source>Fee bump error</source> - <translation>Fee bump error</translation> - </message> - <message> - <source>Increasing transaction fee failed</source> - <translation>İşlem ücreti artırma başarısız oldu</translation> - </message> - <message> - <source>Do you want to increase the fee?</source> - <translation>Ücreti artırmak istiyor musunuz?</translation> - </message> - <message> - <source>Do you want to draft a transaction with fee increase?</source> - <translation>Do you want to draft a transaction with fee increase?</translation> - </message> - <message> - <source>Current fee:</source> - <translation>Şimdiki ücret:</translation> - </message> - <message> - <source>Increase:</source> - <translation>Artış:</translation> - </message> - <message> - <source>New fee:</source> - <translation>Yeni ücret:</translation> - </message> - <message> - <source>Confirm fee bump</source> - <translation>Confirm fee bump</translation> - </message> - <message> - <source>Can't draft transaction.</source> - <translation>Can't draft transaction.</translation> - </message> - <message> - <source>PSBT copied</source> - <translation>PSBT copied</translation> - </message> - <message> - <source>Can't sign transaction.</source> - <translation>İşlem imzalanamıyor.</translation> - </message> - <message> - <source>Could not commit transaction</source> - <translation>Alışveriş taahüt edilemedi.</translation> - </message> - <message> <source>default wallet</source> - <translation>varsayılan cüzdan</translation> + <translation>Varsayılan cüzdan</translation> </message> </context> <context> <name>WalletView</name> <message> <source>&Export</source> - <translation>&Çıkar</translation> + <translation>Dışa aktar</translation> </message> <message> <source>Export the data in the current tab to a file</source> - <translation>Mevcut sekmedeki verileri bir dosyaya aktar</translation> - </message> - <message> - <source>Backup Wallet</source> - <translation>Cüzdanı yedekle</translation> - </message> - <message> - <source>Wallet Data (*.dat)</source> - <translation>Cüzdan Verileri (*.dat)</translation> - </message> - <message> - <source>Backup Failed</source> - <translation>Yedekleme başarısız</translation> + <translation>Geçerli sekmedeki veriyi bir dosyaya dışa aktarın</translation> </message> <message> - <source>There was an error trying to save the wallet data to %1.</source> - <translation>Cüzdan verilerinin %1 konumuna kaydedilmesi sırasında bir hata meydana geldi.</translation> - </message> - <message> - <source>Backup Successful</source> - <translation>Yedekleme tamamlandı</translation> - </message> - <message> - <source>The wallet data was successfully saved to %1.</source> - <translation>Cüzdan verileri %1 konumuna başarıyla kaydedildi.</translation> - </message> - <message> - <source>Cancel</source> - <translation>İptal</translation> + <source>Error</source> + <translation>Hata</translation> </message> -</context> + </context> <context> <name>bitcoin-core</name> - <message> - <source>Distributed under the MIT software license, see the accompanying file %s or %s</source> - <translation>MIT yazılım lisansı altında dağıtılmıştır, beraberindeki %s ya da %s dosyasına bakınız.</translation> - </message> - <message> - <source>Prune configured below the minimum of %d MiB. Please use a higher number.</source> - <translation>Budama, en düşük değer olan %d MiB'den düşük olarak ayarlanmıştır. Lütfen daha yüksek bir sayı kullanınız.</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>Budama: son cüzdan eşleşmesi budanmış verilerin ötesine gitmektedir. -reindex kullanmanız gerekmektedir (Budanmış düğüm ise tüm blok zincirini tekrar indirmeniz gerekir.)</translation> - </message> - <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Hata: Ölümcül dahili bir hata meydana geldi, ayrıntılar için debug.log dosyasına bakınız</translation> - </message> - <message> - <source>Pruning blockstore...</source> - <translation>Blockstore budanıyor...</translation> - </message> - <message> - <source>Unable to start HTTP server. See debug log for details.</source> - <translation>HTTP sunucusu başlatılamadı. Ayrıntılar için debug.log dosyasına bakınız.</translation> - </message> - <message> - <source>The %s developers</source> - <translation>%s ekip</translation> - </message> - <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</translation> - </message> - <message> - <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> - <translation>%s veri dizininde kilit elde edilemedi. %s muhtemelen hâlihazırda çalışmaktadır.</translation> - </message> - <message> - <source>Cannot provide specific connections and have addrman find outgoing connections at the same.</source> - <translation>Cannot provide specific connections and have addrman find outgoing connections at the same.</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>%s dosyasının okunması sırasında bir hata meydana geldi! Tüm anahtarlar doğru bir şekilde okundu, ancak işlem verileri ya da adres defteri ögeleri hatalı veya eksik olabilir.</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>Lütfen bilgisayarınızın saat ve tarihinin doğru olduğunu kontrol ediniz! Saatinizde gecikme varsa %s doğru şekilde çalışamaz.</translation> - </message> - <message> - <source>Please contribute if you find %s useful. Visit %s for further information about the software.</source> - <translation>%s programını faydalı buluyorsanız lütfen katkıda bulununuz. Yazılım hakkında daha fazla bilgi için %s adresini ziyaret ediniz.</translation> - </message> - <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>Blok veritabanı gelecekten gibi görünen bir blok içermektedir. Bu, bilgisayarınızın saat ve tarihinin yanlış ayarlanmış olmasından kaynaklanabilir. Blok veritabanını sadece bilgisayarınızın tarih ve saatinin doğru olduğundan eminseniz yeniden derleyin.</translation> - </message> - <message> - <source>This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> - <translation>Bu kararlı sürümden önceki bir deneme sürümüdür. - risklerini bilerek kullanma sorumluluğu sizdedir - bitcoin oluşturmak ya da ticari uygulamalar için kullanmayınız</translation> - </message> - <message> - <source>This is the transaction fee you may discard if change is smaller than dust at this level</source> - <translation>This is the transaction fee you may discard if change is smaller than dust at this level</translation> - </message> - <message> - <source>Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> - <translation>Unable to replay blocks. You will need to rebuild the database using -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>Veritabanını çatallama öncesi duruma geri sarmak mümkün değil. Blok zincirini tekrar indirmeniz gerekmektedir</translation> - </message> - <message> - <source>Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.</source> - <translation>Uyarı: Ağ üyeleri aralarında tamamen anlaşmış gibi gözükmüyor! Bazı madenciler sorun yaşıyor gibi görünmektedir.</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>Uyarı: Ağ eşlerimizle tamamen anlaşamamışız gibi görünüyor! Güncelleme yapmanız gerekebilir ya da diğer düğümlerin güncelleme yapmaları gerekebilir.</translation> - </message> - <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>son 100 bloğun %d kadarı beklenmeyen versiyona sahip</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s bozuk, geri kazanım başarısız oldu</translation> - </message> - <message> - <source>-maxmempool must be at least %d MB</source> - <translation>-maxmempool en az %d MB olmalıdır</translation> - </message> - <message> - <source>Cannot resolve -%s address: '%s'</source> - <translation>Çözümlenemedi - %s adres: '%s'</translation> - </message> - <message> - <source>Change index out of range</source> - <translation>Aralık dışında değişiklik indeksi</translation> - </message> - <message> - <source>Config setting for %s only applied on %s network when in [%s] section.</source> - <translation>Config setting for %s only applied on %s network when in [%s] section.</translation> - </message> - <message> - <source>Copyright (C) %i-%i</source> - <translation>Copyright (C) %i-%i</translation> - </message> - <message> - <source>Corrupted block database detected</source> - <translation>Bozuk blok veritabanı tespit edildi</translation> - </message> - <message> - <source>Could not find asmap file %s</source> - <translation>Could not find asmap file %s</translation> - </message> - <message> - <source>Could not parse asmap file %s</source> - <translation>Could not parse asmap file %s</translation> - </message> - <message> - <source>Do you want to rebuild the block database now?</source> - <translation>Blok veritabanını şimdi yeniden inşa etmek istiyor musunuz?</translation> - </message> - <message> - <source>Error initializing block database</source> - <translation>Blok veritabanını başlatılırken bir hata meydana geldi</translation> - </message> - <message> - <source>Error initializing wallet database environment %s!</source> - <translation>%s cüzdan veritabanı ortamının başlatılmasında hata meydana geldi!</translation> - </message> - <message> - <source>Error loading %s</source> - <translation>%s unsurunun yüklenmesinde hata oluştu</translation> - </message> - <message> - <source>Error loading %s: Private keys can only be disabled during creation</source> - <translation>%s yüklenirken hata oluştu: Özel anahtarlar yalnızca oluşturma sırasında devre dışı bırakılabilir - </translation> - </message> - <message> - <source>Error loading %s: Wallet corrupted</source> - <translation>%s unsurunun yüklenmesinde hata oluştu: bozuk cüzdan</translation> - </message> - <message> - <source>Error loading %s: Wallet requires newer version of %s</source> - <translation>%s unsurunun yüklenmesinde hata oluştu: cüzdan %s programının yeni bir sürümüne ihtiyaç duyuyor</translation> - </message> - <message> - <source>Error loading block database</source> - <translation>Blok veritabanının yüklenmesinde hata</translation> - </message> - <message> - <source>Error opening block database</source> - <translation>Blok veritabanının açılışı sırasında hata</translation> - </message> - <message> - <source>Failed to listen on any port. Use -listen=0 if you want this.</source> - <translation>Herhangi bir portun dinlenmesi başarısız oldu. Bunu istiyorsanız -listen=0 seçeneğini kullanınız.</translation> - </message> - <message> - <source>Failed to rescan the wallet during initialization</source> - <translation>Başlatma sırasında cüzdanı yeniden tarama işlemi başarısız oldu</translation> - </message> - <message> - <source>Importing...</source> - <translation>İçe aktarılıyor...</translation> - </message> - <message> - <source>Incorrect or no genesis block found. Wrong datadir for network?</source> - <translation>Yanlış ya da bulunamamış doğuş bloğu. Ağ için yanlış veri klasörü mü?</translation> - </message> - <message> - <source>Initialization sanity check failed. %s is shutting down.</source> - <translation>Başlatma sınaması başarısız oldu. %s kapatılıyor.</translation> - </message> - <message> - <source>Invalid P2P permission: '%s'</source> - <translation>Invalid P2P permission: '%s'</translation> - </message> - <message> - <source>Invalid amount for -%s=<amount>: '%s'</source> - <translation>-%s=<tutar> için geçersiz tutar: '%s'</translation> - </message> - <message> - <source>Invalid amount for -discardfee=<amount>: '%s'</source> - <translation>Geçersiz miktarda -discardfee=<amount>:'%s'</translation> - </message> - <message> - <source>Invalid amount for -fallbackfee=<amount>: '%s'</source> - <translation>-fallbackfee=<tutar> için geçersiz tutar: '%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>Unknown address type '%s'</source> - <translation>Bilinmeyen adres türü '%s'</translation> - </message> - <message> - <source>Unknown change type '%s'</source> - <translation>Unknown change type '%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> - <message> - <source>Error: Disk space is too low!</source> - <translation>Error: Disk space is too low!</translation> - </message> - <message> - <source>Loading banlist...</source> - <translation>Ban listesi yükleniyor...</translation> - </message> - <message> - <source>Not enough file descriptors available.</source> - <translation>Kafi derecede dosya tanımlayıcıları mevcut değil.</translation> - </message> - <message> - <source>Prune cannot be configured with a negative value.</source> - <translation>Budama negatif bir değerle yapılandırılamaz.</translation> - </message> - <message> - <source>Prune mode is incompatible with -txindex.</source> - <translation>Budama kipi -txindex ile uyumsuzdur.</translation> - </message> - <message> - <source>Replaying blocks...</source> - <translation>Bloklar tekrar işleniyor...</translation> - </message> - <message> - <source>Rewinding blocks...</source> - <translation>Bloklar geri sarılıyor...</translation> - </message> - <message> - <source>The source code is available from %s.</source> - <translation>Kaynak kod şuradan elde edilebilir: %s.</translation> - </message> - <message> - <source>Transaction fee and change calculation failed</source> - <translation>İşlem ücreti ve para üstü hesaplamasında hata meydana geldi.</translation> - </message> - <message> - <source>Unable to bind to %s on this computer. %s is probably already running.</source> - <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 logging category %s=%s.</source> - <translation>Desteklenmeyen günlük kategorisi %s=%s.</translation> - </message> - <message> - <source>Upgrading UTXO database</source> - <translation>UTXO veritabanı yükseltiliyor</translation> - </message> - <message> - <source>User Agent comment (%s) contains unsafe characters.</source> - <translation>Kullanıcı Aracı açıklaması (%s) güvensiz karakterler içermektedir.</translation> - </message> - <message> - <source>Verifying blocks...</source> - <translation>Bloklar Onaylanıyor...</translation> - </message> - <message> - <source>Wallet needed to be rewritten: restart %s to complete</source> - <translation>%s tamamlanması için cüzdanın yeniden başlatılması gerekiyor</translation> - </message> - <message> - <source>Error: Listening for incoming connections failed (listen returned error %s)</source> - <translation>Hata: İçeri gelen bağlantıların dinlenmesi başarısız oldu (dinleme %s hatasını verdi)</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>-maxtxfee=<tutar> için geçersiz tutar: '%s' (Sıkışmış işlemleri önlemek için en az %s değerinde en düşük aktarım ücretine eşit olmalıdır)</translation> - </message> - <message> - <source>The transaction amount is too small to send after the fee has been deducted</source> - <translation>Bu işlem, tutar düşüldükten sonra göndermek için çok düşük</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>Budama olmayan kipe dönmek için veritabanını -reindex ile tekrar derlemeniz gerekir. Bu, tüm blok zincirini tekrar indirecektir</translation> - </message> - <message> - <source>Error reading from database, shutting down.</source> - <translation>Veritabanı okuma hatası, kapatıldı.</translation> - </message> - <message> - <source>Error upgrading chainstate database</source> - <translation>Zincirdurumu veritabanı yükseltme hatası</translation> - </message> - <message> - <source>Error: Disk space is low for %s</source> - <translation>Error: Disk space is low for %s</translation> - </message> - <message> - <source>Invalid -onion address or hostname: '%s'</source> - <translation>Hatalı -onion adresi ya da host adı: '%s'</translation> - </message> - <message> - <source>Invalid -proxy address or hostname: '%s'</source> - <translation>Geçersiz -proxy adresi veya ana makine adı: '%s'</translation> - </message> - <message> - <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> - <translation>-paytxfee=<tutar>:'%s' unsurunda geçersiz tutar (asgari %s olması lazımdır)</translation> - </message> - <message> - <source>Invalid netmask specified in -whitelist: '%s'</source> - <translation>-whitelist: '%s' unsurunda geçersiz bir ağ maskesi belirtildi</translation> - </message> - <message> - <source>Need to specify a port with -whitebind: '%s'</source> - <translation>-whitebind: '%s' ile bir port belirtilmesi lazımdır</translation> - </message> - <message> - <source>Prune mode is incompatible with -blockfilterindex.</source> - <translation>Prune mode is incompatible with -blockfilterindex.</translation> - </message> - <message> - <source>Reducing -maxconnections from %d to %d, because of system limitations.</source> - <translation>Sistem sınırlamaları sebebiyle -maxconnections %d değerinden %d değerine düşürülmüştür.</translation> - </message> - <message> - <source>Section [%s] is not recognized.</source> - <translation>Section [%s] is not recognized.</translation> - </message> - <message> - <source>Signing transaction failed</source> - <translation>İşlemin imzalanması başarısız oldu</translation> - </message> - <message> - <source>Specified -walletdir "%s" does not exist</source> - <translation>Belirtilen -walletdir "%s" mevcut değil</translation> - </message> - <message> - <source>Specified -walletdir "%s" is a relative path</source> - <translation>Belirtilen -walletdir "%s" göreceli bir yoldur</translation> - </message> - <message> - <source>Specified -walletdir "%s" is not a directory</source> - <translation>Belirtilen -walletdir "%s" bir dizin değildir</translation> - </message> - <message> - <source>The specified config file %s does not exist -</source> - <translation>The specified config file %s does not exist -</translation> - </message> - <message> - <source>The transaction amount is too small to pay the fee</source> - <translation>İşlemdeki bitcoin tutarı ücreti ödemek için çok düşük</translation> - </message> - <message> - <source>This is experimental software.</source> - <translation>Bu deneysel bir yazılımdır.</translation> - </message> - <message> - <source>Transaction amount too small</source> - <translation>İşlem tutarı çok düşük</translation> - </message> - <message> - <source>Transaction too large</source> - <translation>İşlem çok büyük</translation> - </message> - <message> - <source>Unable to bind to %s on this computer (bind returned error %s)</source> - <translation>Bu bilgisayarda %s ögesine bağlanılamadı (bağlanma %s hatasını verdi)</translation> - </message> - <message> - <source>Unable to create the PID file '%s': %s</source> - <translation>Unable to create the PID file '%s': %s</translation> - </message> - <message> - <source>Unable to generate initial keys</source> - <translation>Başlangıç anahtarları üretilemiyor</translation> - </message> - <message> - <source>Unknown -blockfilterindex value %s.</source> - <translation>Unknown -blockfilterindex value %s.</translation> - </message> - <message> - <source>Verifying wallet(s)...</source> - <translation>Cüzdan(lar) onaylanıyor...</translation> - </message> - <message> - <source>Warning: unknown new rules activated (versionbit %i)</source> - <translation>Uyarı: bilinmeyen yeni kurallar etkinleştirilmiştir (versionbit %i)</translation> - </message> - <message> - <source>Zapping all transactions from wallet...</source> - <translation>Cüzdandaki tüm işlemler kaldırılıyor...</translation> - </message> - <message> - <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> - <translation>-maxtxfee çok yüksek bir değere ayarlanmış! Bu denli yüksek ücretler tek bir işlemde ödenebilir.</translation> - </message> - <message> - <source>This is the transaction fee you may pay when fee estimates are not available.</source> - <translation>İşlem ücret tahminleri mevcut olmadığında ödeyebileceğiniz işlem ücreti budur.</translation> - </message> - <message> - <source>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> - <translation>Ağ sürümü zincirinin toplam boyutu (%i) en yüksek boyutu geçmektedir (%i). Kullanıcı aracı açıklamasının sayısı veya boyutunu azaltınız.</translation> - </message> - <message> - <source>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>Uyarı: wallet.dat bozuk, veriler geri kazanıldı! Özgün %s, %s olarak %s klasörüne kaydedildi; bakiyeniz ya da işlemleriniz yanlışsa bir yedeklemeden tekrar yüklemeniz gerekir.</translation> - </message> - <message> - <source>%s is set very high!</source> - <translation>Ayarlanan %s çok yüksek!</translation> - </message> - <message> - <source>Error loading wallet %s. Duplicate -wallet filename specified.</source> - <translation>%s cüzdanı yüklenirken hata oluştu. Belirtilen -wallet dosya adında başka bir kopya daha var.</translation> - </message> - <message> - <source>Starting network threads...</source> - <translation>Bağlantı konuları başlıyor</translation> - </message> - <message> - <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation>Cüzdan minimum değişim ücretinden daha düşük olan ödemeyi önleyecektir</translation> - </message> - <message> - <source>This is the minimum transaction fee you pay on every transaction.</source> - <translation>Her işlem için minimum işlem ücretiniz budur</translation> - </message> - <message> - <source>This is the transaction fee you will pay if you send a transaction.</source> - <translation>Bir işlem göndermeniz durumunda işlem ücretiniz budur</translation> - </message> - <message> - <source>Transaction amounts must not be negative</source> - <translation>İşlem miktarı negatif olmamalı</translation> - </message> - <message> - <source>Transaction has too long of a mempool chain</source> - <translation>İşlem çok uzun bir bellek havuzu zincirine sahip</translation> - </message> - <message> - <source>Transaction must have at least one recipient</source> - <translation>İşlemin en az bir alıcıya sahip olmalı</translation> - </message> - <message> - <source>Unknown network specified in -onlynet: '%s'</source> - <translation>Belirsiz ağ belirtildi -onlynet: '%s'</translation> - </message> - <message> - <source>Insufficient funds</source> - <translation>Yetersiz Bakiye</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>İş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>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>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> - <message> - <source>Loading wallet...</source> - <translation>Cüzdan Bekleniyor...</translation> - </message> - <message> - <source>Cannot downgrade wallet</source> - <translation>Cüzdan indirgenememektedir</translation> - </message> - <message> - <source>Rescanning...</source> - <translation>Tekrar taranıyor...</translation> - </message> - <message> - <source>Done loading</source> - <translation>Yükleme tamamlandı</translation> - </message> -</context> + </context> </TS>
\ No newline at end of file diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts index ca8839fee3..87264deea8 100644 --- a/src/qt/locale/bitcoin_uk.ts +++ b/src/qt/locale/bitcoin_uk.ts @@ -39,7 +39,7 @@ </message> <message> <source>&Export</source> - <translation>&Экспорт</translation> + <translation>&Експортувати</translation> </message> <message> <source>&Delete</source> @@ -70,8 +70,10 @@ <translation>Це ваші адреси Bitcoin для надсилання платежів. Завжди перевіряйте суму та адресу одержувача перед відправленням монет.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Це ваші біткойн-адреси для отримання платежів. Використовуйте кнопку "Створити нову адресу прийому" на вкладці отримання, для створення нових адрес.</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>Це ваші Біткойн адреси для отримання платежів. Використовуйте кнопку "Створити нову адресу для отримання" на вкладці отримання, щоб створити нові адреси. +Підпис можливий лише з адресами типу "legacy".</translation> </message> <message> <source>&Copy Address</source> @@ -91,7 +93,7 @@ </message> <message> <source>Comma separated file (*.csv)</source> - <translation>Файли (*.csv) розділеі комами</translation> + <translation>Файли (*.csv) розділені комами</translation> </message> <message> <source>Exporting Failed</source> @@ -181,7 +183,7 @@ </message> <message> <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> - <translation>Введіть новий пароль для гаманця.<br/> Будь ласка, використовуйте парол з <b>десяти або більше випадкових символів</b>, або <b> вісім або більше слів</b>.</translation> + <translation>Введіть новий пароль для гаманця.<br/> Будь ласка, використовуйте пароль з <b>десяти або більше випадкових символів</b>, або <b> вісім або більше слів</b>.</translation> </message> <message> <source>Enter the old passphrase and new passphrase for the wallet.</source> @@ -399,11 +401,11 @@ </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>Підтвердіть, що Ви є власником повідомлення підписавши його Вашою Bitcoin-адресою</translation> + <translation>Підтвердіть, що Ви є власником повідомлення підписавши його Вашою Біткойн адресою</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>Перевірте повідомлення для впевненості, що воно підписано вказаною Bitcoin-адресою</translation> + <translation>Перевірте повідомлення для впевненості, що воно підписано вказаною Біткойн адресою</translation> </message> <message> <source>&File</source> @@ -482,6 +484,22 @@ <translation>Синхронізовано</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>&Завантажити PSBT з файлу...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>Завантажте Частково Підписану Транзакцію Біткойн</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>Скопіювати PSBT у буфер обміну</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>Завантажте Частково Підписану Біткойн Транзакцію з буфера обміну</translation> + </message> + <message> <source>Node window</source> <translation>Вікно вузлів</translation> </message> @@ -511,19 +529,35 @@ </message> <message> <source>Close Wallet...</source> - <translation>закрити Гаманець ...</translation> + <translation>Закрити Гаманець ...</translation> </message> <message> <source>Close wallet</source> <translation>Закрити гаманець</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>Закрити Всі Гаманці...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>Закрити всі гаманці</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>Показати довідку %1 для отримання переліку можливих параметрів командного рядка.</translation> </message> <message> + <source>&Mask values</source> + <translation>&Значення маски</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>Маскуйте значення на вкладці Огляд</translation> + </message> + <message> <source>default wallet</source> - <translation>гаманець за змовчуванням</translation> + <translation>типовий гаманець</translation> </message> <message> <source>No wallets available</source> @@ -630,8 +664,12 @@ <translation><b>Зашифрований</b> гаманець <b>заблоковано</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Сталася фатальна помилка. Гаманець буде закрито.</translation> + <source>Original message:</source> + <translation>Первинне повідомлення:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>Сталася фатальна помилка. %1 більше не може продовжувати безпечно і вийде.</translation> </message> </context> <context> @@ -835,6 +873,14 @@ <translation>Створити пустий гаманець</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>Використовуйте дескриптори для управління scriptPubKey</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>Дешифрування гаманця</translation> + </message> + <message> <source>Create</source> <translation>Створити</translation> </message> @@ -936,7 +982,7 @@ <name>Intro</name> <message> <source>Welcome</source> - <translation>Добро пожаловать</translation> + <translation>Ласкаво просимо</translation> </message> <message> <source>Welcome to %1.</source> @@ -1006,7 +1052,11 @@ <source>(of %n GB needed)</source> <translation><numerusform>(в той час, як необхідно %n ГБ)</numerusform><numerusform>(в той час, як необхідно %n ГБ)</numerusform><numerusform>(в той час, як необхідно %n ГБ)</numerusform><numerusform>(в той час, як необхідно %n ГБ)</numerusform></translation> </message> - </context> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n ГБ, необхідний для повного ланцюга)</numerusform><numerusform>(%n ГБ, необхідних для повного ланцюга)</numerusform><numerusform>(%n ГБ, необхідних для повного ланцюга)</numerusform><numerusform>(%n ГБ, необхідних для повного ланцюга)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -1089,7 +1139,7 @@ </message> <message> <source>default wallet</source> - <translation>гаманець за змовчуванням</translation> + <translation>типовий гаманець</translation> </message> <message> <source>Opening Wallet <b>%1</b>...</source> @@ -1131,10 +1181,6 @@ <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> @@ -1267,10 +1313,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Підключатися до мережі Bitcoin через окремий SOCKS5 проксі для прихованих сервісів Tor.</translation> - </message> - <message> <source>&Window</source> <translation>&Вікно</translation> </message> @@ -1311,6 +1353,14 @@ <translation>Показати або сховати керування входами.</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>Підключіться до мережі Біткойн через окремий проксі-сервер SOCKS5 для сервісів Tor.</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>Використовуйте окремий проксі-сервер SOCKS&5, щоб дістатися до вузлів через послуги Tor:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>&URL-адреси транзакцій сторонніх розробників</translation> </message> @@ -1445,6 +1495,133 @@ <source>Current total balance in watch-only addresses</source> <translation>Поточний сукупний баланс в адресах для спостереження</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>Режим конфіденційності активований для вкладки Огляд. Щоб демаскувати значення, зніміть прапорець Параметри-> Маскувати значення.</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>Діалог</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>Знак Tx</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>Трансляція Tx</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>Копіювати у буфер обміну</translation> + </message> + <message> + <source>Save...</source> + <translation>Зберегти...</translation> + </message> + <message> + <source>Close</source> + <translation>Завершити</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>Не вдалося завантажити транзакцію: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>Не вдалося підписати транзакцію: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>Не вдалося підписати більше входів.</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>Підписано %1 введення, але все одно потрібно більше підписів.</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>Угода успішно підписана. Транзакція готова до трансляції.</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>Невідома помилка обробки транзакції.</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>Трансакція успішно транслюється! Ідентифікатор транзакції: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>Помилка трансляції транзакції: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT скопійовано в буфер обміну.</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Зберегти дані транзакції</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Частково підписана транзакція (Binary) (* .psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT збережено на диск.</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation>* Надсилає від %1 до %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>Неможливо розрахувати комісію за транзакцію або загальну суму транзакції.</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>Оплачує комісію за транзакцію:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>Всього</translation> + </message> + <message> + <source>or</source> + <translation>або</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>Транзакція містить %1 непідписаних входів.</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>У транзакції бракує певної інформації про вхідні дані.</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>Для транзакції все ще потрібні підпис(и).</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(Але цей гаманець не може підписувати транзакції.)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(Але цей гаманець не має правильних ключів.)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>Транзакція повністю підписана і готова до трансляції.</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>Статус транзакції невідомий.</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1524,7 +1701,7 @@ </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> - <translation>Введіть адресу Bitcoin (наприклад %1)</translation> + <translation>Введіть адресу Біткойн (наприклад %1)</translation> </message> <message> <source>%1 d</source> @@ -1611,6 +1788,10 @@ <translation>Помилка: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>Помилка ініціалізації налаштувань: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 безпечний вихід ще не виконано...</translation> </message> @@ -1709,10 +1890,6 @@ <translation>Ланцюг блоків</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Поточне число блоків</translation> - </message> - <message> <source>Memory Pool</source> <translation>Пул пам'яті</translation> </message> @@ -1757,10 +1934,6 @@ <translation>Виберіть учасника для перегляду детальнішої інформації</translation> </message> <message> - <source>Whitelisted</source> - <translation>В білому списку</translation> - </message> - <message> <source>Direction</source> <translation>Напрямок</translation> </message> @@ -1781,6 +1954,14 @@ <translation>Синхронізовані Блоки</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Картована автономна система, що використовується для диверсифікації вибору вузлів.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>Картована Автономна Система</translation> + </message> + <message> <source>User Agent</source> <translation>Клієнт користувача</translation> </message> @@ -1789,6 +1970,10 @@ <translation>Вікно вузлів</translation> </message> <message> + <source>Current block height</source> + <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> @@ -1801,12 +1986,12 @@ <translation>Збільшити розмір шрифту</translation> </message> <message> - <source>Services</source> - <translation>Сервіси</translation> + <source>Permissions</source> + <translation>Дозволи</translation> </message> <message> - <source>Ban Score</source> - <translation>Очки бану</translation> + <source>Services</source> + <translation>Сервіси</translation> </message> <message> <source>Connection Time</source> @@ -1957,14 +2142,6 @@ <translation>Вихідний</translation> </message> <message> - <source>Yes</source> - <translation>Так</translation> - </message> - <message> - <source>No</source> - <translation>Ні</translation> - </message> - <message> <source>Unknown</source> <translation>Невідома</translation> </message> @@ -2063,56 +2240,60 @@ <source>Copy amount</source> <translation>Копіювати суму</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>Неможливо розблокувати гаманець.</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>Не можливо згенерувати нову %1 адресу</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR-Код</translation> + <source>Request payment to ...</source> + <translation>Запит на оплату до ...</translation> </message> <message> - <source>Copy &URI</source> - <translation>&Скопіювати URI</translation> + <source>Address:</source> + <translation>Адреса:</translation> </message> <message> - <source>Copy &Address</source> - <translation>Скопіювати &адресу</translation> - </message> - <message> - <source>&Save Image...</source> - <translation>&Зберегти зображення...</translation> + <source>Amount:</source> + <translation>Сума:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>Запит платежу на %1</translation> + <source>Label:</source> + <translation>Мітка:</translation> </message> <message> - <source>Payment information</source> - <translation>Інформація про платіж</translation> + <source>Message:</source> + <translation>Повідомлення:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>Гаманець:</translation> </message> <message> - <source>Address</source> - <translation>Адрес</translation> + <source>Copy &URI</source> + <translation>&Скопіювати URI</translation> </message> <message> - <source>Amount</source> - <translation>Сума</translation> + <source>Copy &Address</source> + <translation>Скопіювати &адресу</translation> </message> <message> - <source>Label</source> - <translation>Мітка</translation> + <source>&Save Image...</source> + <translation>&Зберегти зображення...</translation> </message> <message> - <source>Message</source> - <translation>Повідомлення</translation> + <source>Request payment to %1</source> + <translation>Запит платежу на %1</translation> </message> <message> - <source>Wallet</source> - <translation>Гаманець</translation> + <source>Payment information</source> + <translation>Інформація про платіж</translation> </message> </context> <context> @@ -2361,8 +2542,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Ви впевнені, що хочете відправити?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>Перегляньте пропозицію щодо транзакцій. Це призведе до частково підписаної трансакції Bitcoin (PSBT), яку ви можете скопіювати та підписати, наприклад, офлайн-гаманецем %1 або гаманцем, сумісний з PSBT.</translation> + <source>Create Unsigned</source> + <translation>Створити без підпису</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>Зберегти дані транзакції</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>Частково підписана транзакція (Binary) (* .psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT збережено</translation> </message> <message> <source>or</source> @@ -2373,6 +2566,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Ви можете збільшити комісію пізніше (сигналізує Заміна-Через-Комісію, BIP-125).</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Перегляньте свою пропозицію щодо транзакції. Це призведе до частково Підписаної Транзакції Біткойна (PSBT), яку ви можете зберегти або скопіювати, а потім підписати, наприклад, офлайн-гаманцем %1 або апаратним гаманецем, сумісний з PSBT.</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>Будь-ласка, перевірте вашу транзакцію.</translation> </message> @@ -2401,18 +2598,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Підтвердити запропоновану комісію</translation> </message> <message> - <source>Copy PSBT to clipboard</source> - <translation>Скопіювати PSBT у буфер обміну</translation> - </message> - <message> <source>Send</source> <translation>Відправити</translation> </message> <message> - <source>PSBT copied</source> - <translation>PSBT скопійовано</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>Баланс тільки спостереження:</translation> </message> @@ -2489,11 +2678,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Choose previously used address</source> - <translation>Обрати ранiш використовувану адресу</translation> + <translation>Обрати ранiше використану адресу</translation> </message> <message> <source>The Bitcoin address to send the payment to</source> - <translation>Адреса Bitcoin для відправлення платежу</translation> + <translation>Адреса Біткойн для відправлення платежу</translation> </message> <message> <source>Alt+A</source> @@ -2541,7 +2730,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Enter a label for this address to add it to the list of used addresses</source> - <translation>Введіть мітку для цієї адреси для додавання її в список використаних адрес</translation> + <translation>Введіть мітку цієї адреси для додавання її в перелік використаних адрес</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> @@ -2587,7 +2776,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Choose previously used address</source> - <translation>Обрати ранiш використовувану адресу</translation> + <translation>Обрати ранiше використану адресу</translation> </message> <message> <source>Alt+A</source> @@ -3118,7 +3307,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Comma separated file (*.csv)</source> - <translation>Текст, разделённый запятыми (*.csv)</translation> + <translation>Файли (*.csv) розділені комами</translation> </message> <message> <source>Confirmed</source> @@ -3138,11 +3327,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Label</source> - <translation>Метка</translation> + <translation>Мітка</translation> </message> <message> <source>Address</source> - <translation>Адрес</translation> + <translation>Адреса</translation> </message> <message> <source>ID</source> @@ -3150,7 +3339,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Exporting Failed</source> - <translation>Экспорт не удался</translation> + <translation>Помилка експорту</translation> </message> <message> <source>There was an error trying to save the transaction history to %1.</source> @@ -3184,7 +3373,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <name>WalletController</name> <message> <source>Close wallet</source> - <translation>закрити Гаманець</translation> + <translation>Закрити гаманець</translation> </message> <message> <source>Are you sure you wish to close the wallet <i>%1</i>?</source> @@ -3194,12 +3383,26 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Якщо занадто довго закривати гаманець, це може призвести до необхідності повторної синхронізації всієї ланцюга, якщо ввімкнено обрізку.</translation> </message> + <message> + <source>Close all wallets</source> + <translation>Закрити всі гаманці</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>Ви впевнені, що хочете закрити всі гаманці?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>Жоден гаманець не завантажено.</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>Жоден гаманець не завантажений. Перейдіть у меню Файл> Відкрити гаманець, щоб завантажити гаманець. - АБО -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Створити новий гаманець</translation> </message> </context> <context> @@ -3258,18 +3461,42 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>default wallet</source> - <translation>гаманець за змовчуванням</translation> + <translation>типовий гаманець</translation> </message> </context> <context> <name>WalletView</name> <message> <source>&Export</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>Error</source> + <translation>Помилка</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>Не вдається декодувати PSBT з буфера обміну (недійсний base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>Завантажити дані транзакції</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>Частково підписана транзакція (* .psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>Файл PSBT повинен бути менше 100 Мб</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>Не вдається декодувати PSBT</translation> </message> <message> <source>Backup Wallet</source> @@ -3315,10 +3542,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Операція відсікання: остання синхронізація вмісту гаманцю не обмежується діями над скороченими данними. Вам необхідно зробити переіндексацію -reindex (заново завантажити веcь ланцюжок блоків в разі появи скороченого ланцюга)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Помилка: Сталася фатальна помилка (детальніший опис наведено в debug.log)</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Скорочення кількості блоків...</translation> </message> @@ -3331,10 +3554,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Розробники %s</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Неможливо створити ключ зміни адреси. У внутрішній пулі клавіш немає клавіш і жоден ключ не може генерувати.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Неможливо блокувати каталог даних %s. %s, ймовірно, вже працює.</translation> </message> @@ -3347,6 +3566,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Помилка читання %s! Всі ключі зчитано правильно, але записи в адресній книзі, або дані транзакцій можуть бути відсутніми чи невірними.</translation> </message> <message> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation>Надано більше однієї адреси прив'язки служби Tor. Використання %s для автоматично створеної служби Tor.</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>Перевірте правильність дати та часу комп'ютера. Якщо ваш годинник налаштовано невірно, %s не буде працювати належним чином.</translation> </message> @@ -3355,6 +3578,18 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Будь ласка, зробіть внесок, якщо ви знаходите %s корисним. Відвідайте %s для отримання додаткової інформації про програмне забезпечення.</translation> </message> <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase: Не вдалося підготувати оператор для отримання версії схеми гаманця: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>SQLiteDatabase: Не вдалося підготувати оператор для отримання ідентифікатора програми: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <translation>SQLiteDatabase: Невідома версія схеми гаманця %d. Підтримується лише версія %d</translation> + </message> + <message> <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> <translation>Схоже, що база даних блоків містить блок з майбутнього. Це може статися із-за некоректно встановленої дати та/або часу. Перебудовуйте базу даних блоків лише тоді, коли ви переконані, що встановлено правильну дату і час</translation> </message> @@ -3383,14 +3618,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Попередження: неможливо досягти консенсусу з підключеними вузлами! Вам, або іншим вузлам необхідно оновити програмне забезпечення.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d з останніх 100 блоків мають неочікувану версію</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s пошкоджено, відновлення невдале</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool має бути не менше %d МБ</translation> </message> @@ -3467,6 +3694,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Помилка пересканування гаманця під час ініціалізації</translation> </message> <message> + <source>Failed to verify database</source> + <translation>Не вдалося перевірити базу даних</translation> + </message> + <message> <source>Importing...</source> <translation>Імпорт...</translation> </message> @@ -3495,6 +3726,30 @@ 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>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase: Не вдалося виконати оператор для перевірки бази даних: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>QLiteDatabase: Не вдалося отримати версію схеми гаманця: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch the application id: %s</source> + <translation>SQLiteDatabase: Не вдалося отримати ідентифікатор програми: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase: Не вдалося підготувати оператор для перевірки бази даних: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase: Не вдалося прочитати помилку перевірки бази даних: %s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase: Несподіваний ідентифікатор програми. Очікується %u, отримано %u</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation>Зазначений каталог блоків "%s" не існує.</translation> </message> @@ -3515,10 +3770,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Завантаження P2P адрес...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Помилка: замало дискового простору!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Завантаження бан-списку...</translation> </message> @@ -3583,6 +3834,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Помилка: Не вдалося налаштувати прослуховування вхідних підключень (listen повернув помилку: %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s пошкоджено. Спробуйте скористатися інструментом гаманця bitcoin-wallet для відновлення або відновлення резервної копії.</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>Неможливо оновити спліт-гаманець, що не є HD, без оновлення, щоб підтримати попередньо розділений пул ключів. Будь ласка, використовуйте версію 169900 або не вказану версію.</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>Неприпустима сума для -maxtxfee = <amount>: «%s» ( плата повинна бути, принаймні %s, щоб запобігти зависанню транзакцій)</translation> </message> @@ -3591,10 +3850,34 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Залишок від суми транзакції зі сплатою комісії занадто малий</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>Ця помилка може статися, якщо цей гаманець не було чисто вимкнено і востаннє завантажений за допомогою збірки з новою версією Berkeley DB. Якщо так, будь ласка, використовуйте програмне забезпечення, яке востаннє завантажувало цей гаманець</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>Це максимальна комісія за транзакцію, яку ви сплачуєте (на додаток до звичайної комісії), щоб надавати пріоритет частковому уникненню витрат перед регулярним вибором монет.</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>Транзакція потребує наявності адреси для отримання решти, але ми не змогли її згенерувати. Будь ласка, спочатку виконайте регенерацію пулу ключів.</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>Вам необхідно перебудувати базу даних з використанням -reindex для завантаження повного ланцюжка блоків.</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>Виникла фатальна внутрішня помилка, див. debug.log для деталей</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>Неможливо встановити -peerblockfilters без -blockfilterindex.</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>Місця на диску занадто мало!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>Помилка читання бази даних, припиняю роботу.</translation> </message> @@ -3607,6 +3890,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Помилка: для %s бракує місця на диску</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>Помилка: Пул ключів закінчився, потрібно викликати keypoolrefill вдруге</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>Ставка комісії (%s) нижча за встановлену мінімальну ставку комісії (%s)</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>Невірна -onion адреса або ім'я хоста: '%s'</translation> </message> @@ -3627,6 +3918,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Необхідно вказати порт для -whitebind: «%s»</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>Не вказано проксі-сервер. Використовуйте -проксі=<ip> або -проксі=<ip:port>.</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>Використання скороченого ланцюжка блоків несумісне з параметром -blockfilterindex.</translation> </message> @@ -3700,10 +3995,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Попередження: активовано невідомі нові правила (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Видалення всіх транзакцій з гаманця...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>Встановлено дуже велике значення -maxtxfee! Такі великі комісії можуть бути сплачені окремою транзакцією.</translation> </message> @@ -3716,10 +4007,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Загальна довжина рядку мережевої версії (%i) перевищує максимально допустиму (%i). Зменшіть число чи розмір коментарів клієнта користувача.</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>Попередження: файл гаманця пошкоджено, дані врятовано! Оригінальний %s збережено як %s в %s; якщо ваш баланс або транзакції некорректно відображаються, ви повинні відновити його з резервної копії.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s встановлено дуже високо!</translation> </message> @@ -3733,7 +4020,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>The wallet will avoid paying less than the minimum relay fee.</source> - <translation>Кошелёк будет избегать оплат меньших, нежели минимальная комиссия передачи.</translation> + <translation>Гаманець не переведе кошти, якщо комісія становить менше мінімальної плати за транзакцію.</translation> </message> <message> <source>This is the minimum transaction fee you pay on every transaction.</source> @@ -3745,7 +4032,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Transaction amounts must not be negative</source> - <translation>Сумма транзакции не должна быть отрицательной</translation> + <translation>Сума транзакції не повинна бути від'ємною</translation> </message> <message> <source>Transaction has too long of a mempool chain</source> @@ -3764,10 +4051,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>Недостатньо коштів</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>Неможливо оновити не-HD гаманець без оновлення підтримки пулу ключів. Будь-ласка використовуйте -upgradewallet=169900 чи -upgradewallet без вказівки версії. </translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Оцінка комісії не вдалася. Fallbackfee вимкнено. Зачекайте кілька блоків або ввімкніть -fallbackfee.</translation> </message> @@ -3777,7 +4060,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Cannot write to data directory '%s'; check permissions.</source> - <translation>Неможливо записати до каталог даних '%s'; перевірте дозвіл.</translation> + <translation>Неможливо записати до каталогу даних '%s'; перевірте дозвіл.</translation> </message> <message> <source>Loading block index...</source> diff --git a/src/qt/locale/bitcoin_ur.ts b/src/qt/locale/bitcoin_ur.ts index b76551fc6f..647e32749f 100644 --- a/src/qt/locale/bitcoin_ur.ts +++ b/src/qt/locale/bitcoin_ur.ts @@ -62,6 +62,10 @@ <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>&Copy Address</source> <translation>&پتا نقل کریں</translation> </message> @@ -100,10 +104,18 @@ <source>Address</source> <translation>پتہ</translation> </message> - </context> + <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> @@ -115,6 +127,26 @@ <source>Repeat new passphrase</source> <translation>نیا پاس فریز دہرائیں</translation> </message> + <message> + <source>Show passphrase</source> + <translation>پاسفریز دکھائیں</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>بٹوے کو خفیہ کریں</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>ڈکرپٹ والیٹ</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>پاسفریز تبدیل کریں</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>پرس کی خفیہ کاری کی تصدیق کریں</translation> + </message> </context> <context> <name>BanTableModel</name> @@ -140,6 +172,10 @@ <source>Date</source> <translation>تاریخ</translation> </message> + <message> + <source>(no label)</source> + <translation>(کوئی لیبل نہیں)</translation> + </message> </context> <context> <name>CreateWalletActivity</name> @@ -191,6 +227,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -215,20 +254,12 @@ <context> <name>ReceiveRequestDialog</name> <message> - <source>Copy &Address</source> - <translation>کاپی پتہ</translation> - </message> - <message> - <source>Address</source> - <translation>پتہ</translation> - </message> - <message> - <source>Amount</source> - <translation>رقم</translation> + <source>Amount:</source> + <translation>رقم:</translation> </message> <message> - <source>Label</source> - <translation>لیبل</translation> + <source>Copy &Address</source> + <translation>کاپی پتہ</translation> </message> </context> <context> @@ -241,6 +272,10 @@ <source>Label</source> <translation>لیبل</translation> </message> + <message> + <source>(no label)</source> + <translation>(کوئی لیبل نہیں)</translation> + </message> </context> <context> <name>SendCoinsDialog</name> @@ -256,7 +291,11 @@ <source>Balance:</source> <translation>بیلنس:</translation> </message> - </context> + <message> + <source>(no label)</source> + <translation>(کوئی لیبل نہیں)</translation> + </message> +</context> <context> <name>SendCoinsEntry</name> </context> @@ -293,10 +332,18 @@ <source>Label</source> <translation>لیبل</translation> </message> + <message> + <source>(no label)</source> + <translation>(کوئی لیبل نہیں)</translation> + </message> </context> <context> <name>TransactionView</name> <message> + <source>Other</source> + <translation>Other</translation> + </message> + <message> <source>Comma separated file (*.csv)</source> <translation>کاما سے جدا فائلیں (*.csv)</translation> </message> @@ -339,6 +386,10 @@ <source>Export the data in the current tab to a file</source> <translation>موجودہ ڈیٹا کو فائیل میں محفوظ کریں</translation> </message> + <message> + <source>Error</source> + <translation>نقص</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_uz@Cyrl.ts b/src/qt/locale/bitcoin_uz@Cyrl.ts index 4afabdb325..e5dd58d3c8 100644 --- a/src/qt/locale/bitcoin_uz@Cyrl.ts +++ b/src/qt/locale/bitcoin_uz@Cyrl.ts @@ -413,11 +413,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Ҳамён <b>кодланган</b> ва вақтинча <b>қулфланган</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Жиддий хато юз берди. Bitcoin хавфсиз ишлай олмайди, шунинг учун чиқиб кетилади.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -865,7 +861,14 @@ <source>Current total balance in watch-only addresses</source> <translation>Жорий умумий баланс фақат кўринадиган манзилларда</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>or</source> + <translation>ёки</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1021,10 +1024,6 @@ <translation>Хизматлар</translation> </message> <message> - <source>Ban Score</source> - <translation>Тезликни бан қилиш</translation> - </message> - <message> <source>Connection Time</source> <translation>Уланиш вақти</translation> </message> @@ -1093,14 +1092,6 @@ <translation>Ташқи йўналиш</translation> </message> <message> - <source>Yes</source> - <translation>Ҳа</translation> - </message> - <message> - <source>No</source> - <translation>Йўқ</translation> - </message> - <message> <source>Unknown</source> <translation>Номаълум</translation> </message> @@ -1171,12 +1162,20 @@ <source>Copy amount</source> <translation>Кийматни нусхала</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Ҳамён қулфдан чиқмади.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Коди</translation> + <source>Amount:</source> + <translation>Миқдори:</translation> + </message> + <message> + <source>Message:</source> + <translation>Хабар</translation> </message> <message> <source>Copy &Address</source> @@ -1194,30 +1193,6 @@ <source>Payment information</source> <translation>Тўлов маълумоти</translation> </message> - <message> - <source>URI</source> - <translation>URI</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> </context> <context> <name>RecentRequestsTableModel</name> @@ -1793,11 +1768,7 @@ </context> <context> <name>WalletFrame</name> - <message> - <source>No wallet has been loaded.</source> - <translation>Хали бирорта хамён юкланмади</translation> - </message> -</context> + </context> <context> <name>WalletModel</name> <message> @@ -1815,6 +1786,10 @@ <source>Export the data in the current tab to a file</source> <translation>Жорий ички ойна ичидаги маълумотларни файлга экспорт қилиш</translation> </message> + <message> + <source>Error</source> + <translation>Хатолик</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_uz@Latn.ts b/src/qt/locale/bitcoin_uz@Latn.ts index fcdde25df6..93455f2fb3 100644 --- a/src/qt/locale/bitcoin_uz@Latn.ts +++ b/src/qt/locale/bitcoin_uz@Latn.ts @@ -83,6 +83,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -102,14 +105,6 @@ </context> <context> <name>ReceiveRequestDialog</name> - <message> - <source>Address</source> - <translation>Manzil</translation> - </message> - <message> - <source>Label</source> - <translation>Yorliq</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> diff --git a/src/qt/locale/bitcoin_vi.ts b/src/qt/locale/bitcoin_vi.ts index 1d5491137b..192442d6b9 100644 --- a/src/qt/locale/bitcoin_vi.ts +++ b/src/qt/locale/bitcoin_vi.ts @@ -3,7 +3,7 @@ <name>AddressBookPage</name> <message> <source>Right-click to edit address or label</source> - <translation>Phải chuột để sửa địa chỉ hoặc nhãn</translation> + <translation>Nhấn chuột phải để sửa địa chỉ hoặc nhãn</translation> </message> <message> <source>Create a new address</source> @@ -70,10 +70,6 @@ <translation>Đây là những địa chỉ đang thực hiện thanh toán. Luôn kiểm tra số lượng và địa chỉ nhận trước khi gửi coins.</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>Những địa chỉ Bitcoin này để bạn nhận thanh toán. Sử dụng 'Tạo địa chỉ nhận mới'</translation> - </message> - <message> <source>&Copy Address</source> <translation>&Copy Địa Chỉ</translation> </message> @@ -136,6 +132,10 @@ <translation>Lặp lại cụm mật khẩu mới</translation> </message> <message> + <source>Show passphrase</source> + <translation>Hiện cụm từ mật khẩu</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>Ví mã hóa</translation> </message> @@ -176,6 +176,30 @@ <translation>Ví đã được mã hóa</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>Nhập cụm từ mật khẩu mới cho ví điện tử. Hãy sử dụng cụm mật khẩu với mười hoặc nhiều hơn các ký tự ngẫu nhiên, hoặc nhiều hơn tám từ.</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>Nhập cụm mật khẩu cũ và mật khẩu mới cho ví.</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>Xin lưu ý rằng mật mã hóa ví của bạn không thể bảo vệ hoàn toàn bitcoin của bạn khỏi đánh cắp bởi các phẩn mềm gián điệp nhiễm vào máy tính của bạn.</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>Ví sẽ được mã hóa</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>Ví của bạn sẽ được mã hóa.</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>Ví của bạn đã được mã hóa.</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>QUAN TRỌNG: Bất cứ backup nào bạn từng làm trước đây từ ví của bạn nên được thay thế tạo mới, file mã hóa ví. Vì lý do bảo mật, các backup trước đây của các ví chưa mã hóa sẽ bị vô tác dụng ngay khi bạn bắt đầu sử dụng mới, ví đã được mã hóa.</translation> </message> @@ -298,6 +322,14 @@ <translation>Mở &URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>Tạo ví...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>Tạo một ví mới</translation> + </message> + <message> <source>Wallet:</source> <translation>Ví tiền</translation> </message> @@ -446,6 +478,14 @@ <translation>Đã cập nhật</translation> </message> <message> + <source>Node window</source> + <translation>Cửa sổ node</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>Mở dòng lệnh tìm và gỡ lỗi cho node</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&Các địa chỉ đang gửi</translation> </message> @@ -454,6 +494,10 @@ <translation>&Các địa chỉ đang nhận</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>Mở một bitcoin: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>Mớ ví</translation> </message> @@ -581,11 +625,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>Ví thì <b>encrypted</b> và hiện tại <b>locked</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>Một lỗi nghiêm trọng vừa xảy ra. Bitcoin có thể không còn tiếp tục an toàn và sẽ bị bỏ.</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -739,10 +779,58 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Creating Wallet <b>%1</b>...</source> + <translation>Đang tạo ví %1 ...</translation> + </message> + <message> + <source>Create wallet failed</source> + <translation>Tạo ví thất bại</translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>Cảnh báo khi tạo ví</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>Tạo Ví</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>Tên Ví</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>Mật mã hóa ví. Ví sẽ được mật mã hóa với cụm mật khẩu của bạn.</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>Mật mã hóa ví</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>Tắt các khóa cá nhân cho ví này. Các ví với khóa cá nhân tắt sẽ không có các khóa cá nhân và không thể có nhân HD hoặc nhập thêm khóa cá nhân. Việc này tốt cho các ví chỉ dùng để xem.</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>Vô hiệu hóa khóa cá nhân</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>Tạo một ví trống. Ví trống không có các khóa cá nhân hay script ban đầu. Khóa cá nhân và địa chỉ có thể được nhập, hoặc một nhân HD có thể được thiết lập sau đó.</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>Tạo ví trống</translation> + </message> + <message> + <source>Create</source> + <translation>Tạo</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> @@ -855,6 +943,10 @@ <translation>Khi bạn click OK, %1 sẽ bắt đầu download và process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>Đảo ngược lại thiết lập này yêu cầu download lại toàn bộ blockchain. Download toàn bộ blockchain trước và loại nó sau đó sẽ nhanh hơn. Vô hiệu hóa một số tính năng nâng cao.</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>Đồng bộ hóa ban đầu này rất đòi hỏi, và có thể phơi bày các sự cố về phần cứng với máy tính của bạn trước đó đã không được chú ý. Mỗi khi bạn chạy %1, nó sẽ tiếp tục tải về nơi nó dừng lại.</translation> </message> @@ -906,7 +998,11 @@ <source>(of %n GB needed)</source> <translation><numerusform>(of %n GB cần thiết)</numerusform></translation> </message> - </context> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(%n GB cần cho toàn blockchain)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -954,6 +1050,14 @@ <translation>Ẩn</translation> </message> <message> + <source>Esc</source> + <translation>Esc</translation> + </message> + <message> + <source>%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source> + <translation>%1 đang được đồng bộ. Header và block sẽ được download từ các nốt lân cận và thẩm định tới khi đạt đỉnh của blockchain.</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>Không biết. Đang đồng bộ Headers (%1, %2%)...</translation> </message> @@ -961,6 +1065,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>Mở bitcoin URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -968,6 +1076,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>Mở ví thất bại</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>Mở ví cảnh báo</translation> + </message> + <message> <source>default wallet</source> <translation>ví mặc định</translation> </message> @@ -1011,10 +1127,6 @@ <translation>Hiển thị nếu cung cấp default SOCKS5 proxy is used to reach peers via this network type.</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>Dùng riêng lẻ proxy SOCKS&5 để nối tới nốt mạng khác qua dịch vị ẩn Tor:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>Ẩn biểu tượng ở khay hệ thống</translation> </message> @@ -1147,10 +1259,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>Kết nối đến Bitcoin network qua một nhánh rời SOCKS5 proxy của Tor hidden services.</translation> - </message> - <message> <source>&Window</source> <translation>&Window</translation> </message> @@ -1325,7 +1433,18 @@ <source>Current total balance in watch-only addresses</source> <translation>Tổng số dư hiện tại trong watch-only addresses</translation> </message> -</context> + </context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Total Amount</source> + <translation>Tổng số</translation> + </message> + <message> + <source>or</source> + <translation>hoặc</translation> + </message> + </context> <context> <name>PaymentServer</name> <message> @@ -1345,6 +1464,18 @@ <translation>'bitcoin://' không khả dụng URI. Dùng thay vì 'bitcoin:' .</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>Không thể tiến hần yêu cầu giao dịch vì BIP70 không được hỗ trợ.</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>Do lỗ hổng bảo mật lan rộng của BIP70, bạn được khuyến cáo mạnh mẽ rằng bất kỳ hướng dẫn thương mại để chuyển ví đều bị bỏ qua.</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>Nếu bạn nhận được lỗi này, bạn nên yêu cầu của hàng cung cấp một BIP21 tương thích URI.</translation> + </message> + <message> <source>Invalid payment address %1</source> <translation>Invalid payment address %1</translation> </message> @@ -1577,10 +1708,6 @@ <translation>Block chain</translation> </message> <message> - <source>Current number of blocks</source> - <translation>Số blocks hiện tại</translation> - </message> - <message> <source>Memory Pool</source> <translation>Pool Bộ Nhớ</translation> </message> @@ -1625,10 +1752,6 @@ <translation>Chọn một peer để xem thông tin chi tiết.</translation> </message> <message> - <source>Whitelisted</source> - <translation>Whitelisted</translation> - </message> - <message> <source>Direction</source> <translation>Direction</translation> </message> @@ -1649,10 +1772,22 @@ <translation>Blocks đã được đồng bộ</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>Hệ thống tự động ánh xạ được sử dụng để đa dạng hóa lựa chọn ngang hàng.</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>AS đã được map</translation> + </message> + <message> <source>User Agent</source> <translation>User đặc vụ</translation> </message> <message> + <source>Node window</source> + <translation>Cửa sổ node</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>Mở cái %1 debug log file từ danh mục dữ liệu hiện tại. Điều này cần vài giây cho large log files.</translation> </message> @@ -1669,10 +1804,6 @@ <translation>Dịch vụ</translation> </message> <message> - <source>Ban Score</source> - <translation>Cấm Score</translation> - </message> - <message> <source>Connection Time</source> <translation>Connection Thời Gian</translation> </message> @@ -1821,14 +1952,6 @@ <translation>Outbound</translation> </message> <message> - <source>Yes</source> - <translation>Yes</translation> - </message> - <message> - <source>No</source> - <translation>No</translation> - </message> - <message> <source>Unknown</source> <translation>Không biết</translation> </message> @@ -1864,6 +1987,14 @@ <translation>Một optional giá trị để request. Để lại đây khoảng trống hoặc zero để không request một giá trị xác định.</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>Một nhãn tùy chọn để liên kết với địa chỉ nhận mới (được bạn sử dụng để xác định hóa đơn). Nó cũng được đính kèm với yêu cầu thanh toán.</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>Một thông báo tùy chọn được đính kèm với yêu cầu thanh toán và có thể được hiển thị cho người gửi.</translation> + </message> + <message> <source>&Create new receiving address</source> <translation>&Tạo địa chỉ nhận mới</translation> </message> @@ -1876,6 +2007,14 @@ <translation>Xóa</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>Các địa chỉ segwit gốc (còn gọi là Bech32 hoặc BIP-173) sẽ giảm phí giao dịch của bạn sau này và bảo vệ tốt hơn trước các lỗi chính tả, nhưng ví cũ không hỗ trợ chúng. Khi không được chọn, một địa chỉ tương thích với ví cũ sẽ được tạo thay thế.</translation> + </message> + <message> + <source>Generate native segwit (Bech32) address</source> + <translation>Tạo địa chỉ segwit (Bech32) riêng</translation> + </message> + <message> <source>Requested payments history</source> <translation>Yêu cầu lịch sử giao dịch</translation> </message> @@ -1911,12 +2050,24 @@ <source>Copy amount</source> <translation>Sao chép số lượng</translation> </message> -</context> + <message> + <source>Could not unlock wallet.</source> + <translation>Không thể unlock wallet.</translation> + </message> + </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Code</translation> + <source>Amount:</source> + <translation>Số lượng:</translation> + </message> + <message> + <source>Message:</source> + <translation>Tin nhắn:</translation> + </message> + <message> + <source>Wallet:</source> + <translation>Ví tiền</translation> </message> <message> <source>Copy &URI</source> @@ -1938,30 +2089,6 @@ <source>Payment information</source> <translation>Payment thông tin</translation> </message> - <message> - <source>URI</source> - <translation>URI</translation> - </message> - <message> - <source>Address</source> - <translation>Địa chỉ</translation> - </message> - <message> - <source>Amount</source> - <translation>Số lượng</translation> - </message> - <message> - <source>Label</source> - <translation>Nhãn</translation> - </message> - <message> - <source>Message</source> - <translation>Tin nhắn</translation> - </message> - <message> - <source>Wallet</source> - <translation>Ví</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> @@ -2109,6 +2236,10 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Rác:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>Ẩn cài đặt phí giao dịch</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>Khi có khối lượng giao dịch ít hơn chổ trống trong các khối, các nhà đào mỏ cũng như các nút chuyển tiếp có thể thực thi chỉ với một khoản phí tối thiểu. Chỉ trả khoản phí tối thiểu này là tốt, nhưng lưu ý rằng điều này có thể dẫn đến một giao dịch không bao giờ xác nhận một khi có nhu cầu giao dịch bitcoin nhiều hơn khả năng mạng có thể xử lý.</translation> </message> @@ -2177,6 +2308,14 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>%1 (%2 blocks)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Cr&eate không được ký</translation> + </message> + <message> + <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>Tạo Giao dịch Bitcoin được ký một phần (PSBT) để sử dụng với các dạng như: ví ngoại tuyến %1 hoặc ví phần cứng tương thích PSBT.</translation> + </message> + <message> <source> from wallet '%1'</source> <translation>từ ví '%1'</translation> </message> @@ -2189,6 +2328,10 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>%1 đến%2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>Bạn có muốn tạo tạm thời dao dịch này?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>Bạn chắc chắn muốn gửi chứ?</translation> </message> @@ -2225,6 +2368,18 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Confirm gửi coins</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>Xác nhận đề xuất giao dịch</translation> + </message> + <message> + <source>Send</source> + <translation>Gửi</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>Số dư chỉ xem:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> <translation>Địa chỉ người nhận address thì không valid. Kiểm tra lại đi.</translation> </message> @@ -2320,6 +2475,10 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Xóa bỏ entry này</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>Lượng tiền để gửi trong mỗi đơn vị đã chọn</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>The fee sẽ được khấu trừ từ số tiền đang gửi. Người nhận sẽ receive ít bitcoins hơn bạn gõ vào khoảng trống. Nếu nhiều người gửi được chọn, fee sẽ được chia đều.</translation> </message> @@ -2446,6 +2605,14 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>The Bitcoin address tin nhắn đã ký với</translation> </message> <message> + <source>The signed message to verify</source> + <translation>Tin nhắn đã được ký để xác nhận</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>Chữ ký được cung cấp khi tin nhắn đã được ký</translation> + </message> + <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> <translation>Verify tin nhắn để chắc rằng nó đã được ký với xác định Bitcoin address</translation> </message> @@ -2478,6 +2645,10 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Wallet unlock đã được hủy.</translation> </message> <message> + <source>No error</source> + <translation>Không lỗi</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> <translation>Private key cho address đã nhập thì không có sẵn.</translation> </message> @@ -2652,6 +2823,10 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Output index</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(Chứng chỉ chưa được thẩm định)</translation> + </message> + <message> <source>Merchant</source> <translation>Merchant</translation> </message> @@ -2975,15 +3150,19 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Đông ví</translation> </message> <message> + <source>Are you sure you wish to close the wallet <i>%1</i>?</source> + <translation>Bạn có chắc bạn muốn đóng ví %1 ?</translation> + </message> + <message> <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>Đóng ví thời gian dài sẽ dẫn đến phải đồng bộ hóa lại cả chuỗi nếu cắt tỉa pruning được kích hoạt</translation> </message> -</context> + </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>No wallet has been loaded.</translation> + <source>Create a new wallet</source> + <translation>Tạo một ví mới</translation> </message> </context> <context> @@ -3005,6 +3184,10 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Do you want to increase the fee?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>Bạn có muốn tạo tạm thời một giao dịch với phí tăng?</translation> + </message> + <message> <source>Current fee:</source> <translation>Current fee:</translation> </message> @@ -3021,6 +3204,14 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Confirm fee bump</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>Không thể tạo tạm giao dịch.</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>Đã sao chép PSBT</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>Can't sign transaction.</translation> </message> @@ -3044,6 +3235,10 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Xuất dữ liệu trong thẻ hiện tại ra file</translation> </message> <message> + <source>Error</source> + <translation>Lỗi</translation> + </message> + <message> <source>Backup Wallet</source> <translation>Backup Wallet</translation> </message> @@ -3087,10 +3282,6 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>Error: A fatal internal error occurred, see debug.log for details</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>Pruning blockstore...</translation> </message> @@ -3103,10 +3294,6 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>The %s developers</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>Không thể tạo khóa địa chỉ thay đổi. Không có các khóa trong hồ khóa keypool nội bộ và không thể tạo bất kì khóa nào.</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>Cannot obtain a lock on data directory %s. %s is probably already running.</translation> </message> @@ -3155,14 +3342,6 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>%d of last 100 blocks have unexpected version</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s corrupt, salvage failed</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool must be at least %d MB</translation> </message> @@ -3187,6 +3366,14 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Corrupted block database detected</translation> </message> <message> + <source>Could not find asmap file %s</source> + <translation>Không tìm thấy tệp asmap %s</translation> + </message> + <message> + <source>Could not parse asmap file %s</source> + <translation>Không đọc được tệp asmap %s</translation> + </message> + <message> <source>Do you want to rebuild the block database now?</source> <translation>Do you want to rebuild the block database now?</translation> </message> @@ -3263,6 +3450,14 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Thư mục chứa các khối được chỉ ra "%s" không tồn tại</translation> </message> <message> + <source>Unknown address type '%s'</source> + <translation>Không biết địa chỉ kiểu '%s'</translation> + </message> + <message> + <source>Unknown change type '%s'</source> + <translation>Không biết thay đổi kiểu '%s'</translation> + </message> + <message> <source>Upgrading txindex database</source> <translation>Đang nâng cấp dữ liệu txindex</translation> </message> @@ -3271,10 +3466,6 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Loading P2P addresses...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>Lỗi: Chổ tróng đĩa lưu trữ còn quá ít!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>Loading banlist...</translation> </message> @@ -3457,10 +3648,6 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Warning: unknown new rules activated (versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>Zapping all transactions from wallet...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</translation> </message> @@ -3473,10 +3660,6 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</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>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.</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s is set very high!</translation> </message> @@ -3521,10 +3704,6 @@ Lưu ý: Vì phí được tính trên cơ sở mỗi byte, nên phí "100 satos <translation>Không đủ tiền</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>Không thể nâng cấp một địa chỉ HD tách rời mà không nâng cấp hỗ trợ keypool tách rời trước. Làm ơn dùng upgradewallet=169900 hoặc -upgradewallet với không có chỉ ra phiên bản.</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>Dự toán phí không thành công. Fallbackfee bị vô hiệu hóa. Đợi sau một vài khối hoặc kích hoạt -fallbackfee.</translation> </message> diff --git a/src/qt/locale/bitcoin_yo.ts b/src/qt/locale/bitcoin_yo.ts index 7094d2b3b4..f3f95ecb5f 100644 --- a/src/qt/locale/bitcoin_yo.ts +++ b/src/qt/locale/bitcoin_yo.ts @@ -87,6 +87,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> diff --git a/src/qt/locale/bitcoin_zh-Hans.ts b/src/qt/locale/bitcoin_zh-Hans.ts index 5e2595eea3..93335756f2 100644 --- a/src/qt/locale/bitcoin_zh-Hans.ts +++ b/src/qt/locale/bitcoin_zh-Hans.ts @@ -30,6 +30,10 @@ <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> @@ -66,6 +70,12 @@ <translation>这是你的比特币发币地址。发送前请确认发送数量和接收地址</translation> </message> <message> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>这是你的比特币接收地址。点击接收选项卡中“创建新的接收地址”按钮来创建新的地址。 +签名只能使用“传统”类型的地址。</translation> + </message> + <message> <source>&Copy Address</source> <translation>复制地址</translation> </message> @@ -112,9 +122,41 @@ <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>Show passphrase</source> + <translation>显示密码</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> </context> <context> <name>BanTableModel</name> @@ -163,6 +205,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -182,14 +227,6 @@ </context> <context> <name>ReceiveRequestDialog</name> - <message> - <source>Address</source> - <translation>地址</translation> - </message> - <message> - <source>Label</source> - <translation>标签</translation> - </message> </context> <context> <name>RecentRequestsTableModel</name> diff --git a/src/qt/locale/bitcoin_zh.ts b/src/qt/locale/bitcoin_zh.ts index 409cb3a2bb..f67c74ec21 100644 --- a/src/qt/locale/bitcoin_zh.ts +++ b/src/qt/locale/bitcoin_zh.ts @@ -132,6 +132,10 @@ <translation>重复新密码</translation> </message> <message> + <source>Show passphrase</source> + <translation>显示密码</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>加密钱包</translation> </message> @@ -172,6 +176,30 @@ <translation>加密钱包</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>输入钱包的新密码。<br/>密码中请使用<b>10个或更多随机字符</b>,或<b>8个或更多的单词</b>。</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>输入钱包的旧密码和新密码。</translation> + </message> + <message> + <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> + <translation>记住,加密您的钱包并不能完全保护您的比特币不被您电脑中的恶意软件窃取。</translation> + </message> + <message> + <source>Wallet to be encrypted</source> + <translation>钱包即将被加密编码。</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>你的钱包即将被加密编码。</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>你的钱包已被加密编码。</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> @@ -290,6 +318,14 @@ <translation>打开 &URI...</translation> </message> <message> + <source>Create Wallet...</source> + <translation>创建钱包</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>创建一个新的钱包</translation> + </message> + <message> <source>Wallet:</source> <translation>钱包:</translation> </message> @@ -393,6 +429,10 @@ <source>&Command-line options</source> <translation>&命令行选项</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> @@ -401,6 +441,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></translation> + </message> <message> <source>%1 behind</source> <translation>%1 落后</translation> @@ -430,6 +474,14 @@ <translation>最新的</translation> </message> <message> + <source>Node window</source> + <translation>结点窗口</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>打开结点的调试和诊断控制台</translation> + </message> + <message> <source>&Sending addresses</source> <translation>&发送地址</translation> </message> @@ -438,6 +490,10 @@ <translation>&接受地址</translation> </message> <message> + <source>Open a bitcoin: URI</source> + <translation>打开比特币: URI</translation> + </message> + <message> <source>Open Wallet</source> <translation>打开钱包</translation> </message> @@ -490,6 +546,10 @@ <translation>连接到节点...</translation> </message> <message> + <source>Catching up...</source> + <translation>跟进中</translation> + </message> + <message> <source>Date: %1 </source> <translation>日期:%1 @@ -553,11 +613,7 @@ <source>Wallet is <b>encrypted</b> and currently <b>locked</b></source> <translation>钱包是<b>加密的</b>,目前<b>已锁定</b></translation> </message> - <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>发生了致命错误。比特币无法继续安全运行,将退出。</translation> - </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -609,6 +665,14 @@ <translation>总计</translation> </message> <message> + <source>Received with label</source> + <translation>收到,夹带标签</translation> + </message> + <message> + <source>Received with address</source> + <translation>收到,夹带地址</translation> + </message> + <message> <source>Date</source> <translation>日期</translation> </message> @@ -694,6 +758,38 @@ </context> <context> <name>CreateWalletDialog</name> + <message> + <source>Create Wallet</source> + <translation>创建钱包</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>钱包名称</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>编码钱包。钱包将会根据你选择的密码进行加密编码。</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>加密钱包</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>禁用这个钱包的私钥。禁用私钥的钱包将没有私钥,也不能使用HD种子或者导入的私钥。对于仅供查看的钱包这是理想的设置。</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>禁用私钥</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>创建一个空白钱包。空白钱包没有起始的私钥和脚本。稍后可以倒入私钥和地址、设置HD种子。</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>创建空白钱包</translation> + </message> </context> <context> <name>EditAddressDialog</name> @@ -943,6 +1039,9 @@ </message> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -961,6 +1060,10 @@ <context> <name>RPCConsole</name> <message> + <source>Node window</source> + <translation>结点窗口</translation> + </message> + <message> <source>Last block time</source> <translation>最后的区块时间</translation> </message> @@ -1007,20 +1110,20 @@ <source>Copy amount</source> <translation>复制金额</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>Address</source> - <translation>地址</translation> + <source>Could not unlock wallet.</source> + <translation>不能解锁钱包</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Amount</source> - <translation>总计</translation> + <source>Amount:</source> + <translation>总计:</translation> </message> <message> - <source>Label</source> - <translation>标签</translation> + <source>Wallet:</source> + <translation>钱包:</translation> </message> </context> <context> @@ -1328,7 +1431,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </context> <context> <name>WalletFrame</name> - </context> + <message> + <source>Create a new wallet</source> + <translation>创建一个新的钱包</translation> + </message> +</context> <context> <name>WalletModel</name> <message> @@ -1346,6 +1453,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Export the data in the current tab to a file</source> <translation>将当前选项卡中的数据导出到文件</translation> </message> + <message> + <source>Error</source> + <translation>错误</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index 2c534d9162..fedc4a9c80 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -70,8 +70,10 @@ <translation>您可以给这些比特币地址付款。在付款之前,务必要检查金额和收款地址是否正确。</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>您可以用这些比特币地址收款。使用“接收”标签页中的"创建新收款地址"按钮创建新地址。</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>这是您用来收款的比特币地址。使用“接收”标签页中的“创建新收款地址”按钮来创建新的收款地址。 +只有“传统(legacy)”类型的地址支持签名。</translation> </message> <message> <source>&Copy Address</source> @@ -482,6 +484,22 @@ <translation>已是最新</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>从文件加载PSBT...(&L)</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>加载部分签名比特币交易(PSBT)</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>从剪贴板加载PSBT...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>从剪贴板中加载部分签名比特币交易(PSBT)</translation> + </message> + <message> <source>Node window</source> <translation>节点窗口</translation> </message> @@ -518,10 +536,26 @@ <translation>关闭钱包</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>关闭所有钱包...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>关闭所有钱包</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>显示 %1 帮助信息,获取可用命令行选项列表</translation> </message> <message> + <source>&Mask values</source> + <translation>不明文显示数值(&M)</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>在“概况”标签页中不明文显示数值、只显示掩码</translation> + </message> + <message> <source>default wallet</source> <translation>默认钱包</translation> </message> @@ -630,8 +664,12 @@ <translation>钱包已被<b>加密</b>,当前为<b>锁定</b>状态</translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>发生严重错误。客户端无法安全地继续运行,即将退出。</translation> + <source>Original message:</source> + <translation>原消息:</translation> + </message> + <message> + <source>A fatal error occurred. %1 can no longer continue safely and will quit.</source> + <translation>发生致命错误。%1 已经无法继续安全运行并即将退出。</translation> </message> </context> <context> @@ -835,6 +873,14 @@ <translation>创建空白钱包</translation> </message> <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>使用输出描述符进行scriptPubKey管理</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>输出描述符钱包</translation> + </message> + <message> <source>Create</source> <translation>创建</translation> </message> @@ -1120,7 +1166,7 @@ </message> <message> <source>&Start %1 on system login</source> - <translation>系统登入时启动 %1 (%S)</translation> + <translation>系统登入时启动 %1 (&S)</translation> </message> <message> <source>Size of &database cache</source> @@ -1139,10 +1185,6 @@ <translation>显示默认的SOCKS5代理是否被用于在该类型的网络下连接同伴。</translation> </message> <message> - <source>Use separate SOCKS&5 proxy to reach peers via Tor hidden services:</source> - <translation>连接Tor隐藏服务节点时使用另一个SOCKS&5代理:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>不在系统通知区域显示图标。</translation> </message> @@ -1275,10 +1317,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>通过 Tor 隐藏服务连接比特币网络时使用另一个 SOCKS5 代理。</translation> - </message> - <message> <source>&Window</source> <translation>窗口(&W)</translation> </message> @@ -1319,6 +1357,14 @@ <translation>是否显示手动选币功能。</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>连接比特币网络时专门为Tor onion服务使用另一个 SOCKS5 代理。</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>连接Tor onion服务节点时使用另一个SOCKS&5代理:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>第三方交易网址(&T)</translation> </message> @@ -1453,6 +1499,133 @@ <source>Current total balance in watch-only addresses</source> <translation>仅观察地址中的当前总余额</translation> </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>“概况”标签页已启用隐私模式。要明文显示数值,请在设置中取消勾选“不明文显示数值”。</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>会话</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>签名交易</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>广播交易</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>复制到剪贴板</translation> + </message> + <message> + <source>Save...</source> + <translation>保存...</translation> + </message> + <message> + <source>Close</source> + <translation>关闭</translation> + </message> + <message> + <source>Failed to load transaction: %1</source> + <translation>加载交易失败: %1</translation> + </message> + <message> + <source>Failed to sign transaction: %1</source> + <translation>签名交易失败: %1</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>没有交易输入项可供签名了。</translation> + </message> + <message> + <source>Signed %1 inputs, but more signatures are still required.</source> + <translation>已签名 %1 个交易输入项,但是仍然还有余下的项目需要签名。</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>成功签名交易。交易已经可以广播。</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>处理交易时遇到未知错误。</translation> + </message> + <message> + <source>Transaction broadcast successfully! Transaction ID: %1</source> + <translation>已成功广播交易!交易ID: %1</translation> + </message> + <message> + <source>Transaction broadcast failed: %1</source> + <translation>交易广播失败: %1</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>已复制PSBT到剪贴板</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>保存交易数据</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>部分签名交易(二进制) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT已保存到硬盘</translation> + </message> + <message> + <source> * Sends %1 to %2</source> + <translation> * 发送 %1 至 %2</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>无法计算交易费用或总交易金额。</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>支付交易费用:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>总额</translation> + </message> + <message> + <source>or</source> + <translation>或</translation> + </message> + <message> + <source>Transaction has %1 unsigned inputs.</source> + <translation>交易中含有%1个未签名输入项。</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>交易中有输入项缺失某些信息。</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>交易仍然需要签名。</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(但这个钱包不能签名交易)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(但这个钱包没有正确的密钥)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>交易已经完全签名,可以广播。</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>交易状态未知。</translation> + </message> </context> <context> <name>PaymentServer</name> @@ -1619,6 +1792,10 @@ <translation>错误: %1</translation> </message> <message> + <source>Error initializing settings: %1</source> + <translation>初始化设置出错: %1</translation> + </message> + <message> <source>%1 didn't yet exit safely...</source> <translation>%1 尚未安全退出...</translation> </message> @@ -1717,10 +1894,6 @@ <translation>区块链</translation> </message> <message> - <source>Current number of blocks</source> - <translation>当前区块数量</translation> - </message> - <message> <source>Memory Pool</source> <translation>内存池</translation> </message> @@ -1765,10 +1938,6 @@ <translation>选择节点查看详细信息。</translation> </message> <message> - <source>Whitelisted</source> - <translation>白名单</translation> - </message> - <message> <source>Direction</source> <translation>方向</translation> </message> @@ -1789,6 +1958,14 @@ <translation>已同步区块</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>映射到的自治系统,被用来多样化选择节点</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>映射到的AS</translation> + </message> + <message> <source>User Agent</source> <translation>用户代理</translation> </message> @@ -1797,6 +1974,10 @@ <translation>节点窗口</translation> </message> <message> + <source>Current block height</source> + <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> @@ -1809,12 +1990,12 @@ <translation>放大字体大小</translation> </message> <message> - <source>Services</source> - <translation>服务</translation> + <source>Permissions</source> + <translation>权限</translation> </message> <message> - <source>Ban Score</source> - <translation>封禁记分</translation> + <source>Services</source> + <translation>服务</translation> </message> <message> <source>Connection Time</source> @@ -1965,14 +2146,6 @@ <translation>传出</translation> </message> <message> - <source>Yes</source> - <translation>是</translation> - </message> - <message> - <source>No</source> - <translation>否</translation> - </message> - <message> <source>Unknown</source> <translation>未知</translation> </message> @@ -2071,56 +2244,60 @@ <source>Copy amount</source> <translation>复制金额</translation> </message> + <message> + <source>Could not unlock wallet.</source> + <translation>无法解锁钱包。</translation> + </message> + <message> + <source>Could not generate new %1 address</source> + <translation>无法生成新的%1地址</translation> + </message> </context> <context> <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>二维码</translation> - </message> - <message> - <source>Copy &URI</source> - <translation>复制 &URI</translation> + <source>Request payment to ...</source> + <translation>请求付款到 ...</translation> </message> <message> - <source>Copy &Address</source> - <translation>复制地址(&A)</translation> + <source>Address:</source> + <translation>地址:</translation> </message> <message> - <source>&Save Image...</source> - <translation>保存图像(&S)...</translation> + <source>Amount:</source> + <translation>金额:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>请求付款到 %1</translation> + <source>Label:</source> + <translation>标签:</translation> </message> <message> - <source>Payment information</source> - <translation>付款信息</translation> + <source>Message:</source> + <translation>消息:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>钱包:</translation> </message> <message> - <source>Address</source> - <translation>地址</translation> + <source>Copy &URI</source> + <translation>复制 &URI</translation> </message> <message> - <source>Amount</source> - <translation>金额</translation> + <source>Copy &Address</source> + <translation>复制地址(&A)</translation> </message> <message> - <source>Label</source> - <translation>标签</translation> + <source>&Save Image...</source> + <translation>保存图像(&S)...</translation> </message> <message> - <source>Message</source> - <translation>消息</translation> + <source>Request payment to %1</source> + <translation>请求付款到 %1</translation> </message> <message> - <source>Wallet</source> - <translation>钱包</translation> + <source>Payment information</source> + <translation>付款信息</translation> </message> </context> <context> @@ -2346,7 +2523,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>创建一个“部分签名比特币交易”(PSBT),以用于像是离线%1钱包,或是兼容PSBT的硬件钱包这种用途。</translation> + <translation>创建一个“部分签名比特币交易”(PSBT),以用于诸如离线%1钱包,或是兼容PSBT的硬件钱包这类用途。</translation> </message> <message> <source> from wallet '%1'</source> @@ -2369,8 +2546,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>您确定要发出吗?</translation> </message> <message> - <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> - <translation>请务必要审核您的交易提案。这将会产生一笔“部分签名比特币交易”(PSBT),您可以复制它,然后可以通过各种方式对它进行签名,比如,可以通过离线%1钱包或是兼容PSBT的硬件钱包来完成签名。</translation> + <source>Create Unsigned</source> + <translation>创建未签名交易</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>保存交易数据</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>部分签名交易(二进制) (*.psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>已保存PSBT</translation> </message> <message> <source>or</source> @@ -2381,6 +2570,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>你可以后来再追加手续费(打上支持BIP-125手续费追加的标记)</translation> </message> <message> + <source>Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source> + <translation>请务必仔细检查您的交易请求。这会产生一个部分签名比特币交易(PSBT),可以把保存下来或复制出去,然后就可以对它进行签名,比如用离线%1钱包,或是用兼容PSBT的硬件钱包。</translation> + </message> + <message> <source>Please, review your transaction.</source> <translation>请检查您的交易。</translation> </message> @@ -2406,21 +2599,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Confirm transaction proposal</source> - <translation>确认交易提案</translation> - </message> - <message> - <source>Copy PSBT to clipboard</source> - <translation>复制PSBT到剪贴板</translation> + <translation>确认交易请求</translation> </message> <message> <source>Send</source> <translation>发送</translation> </message> <message> - <source>PSBT copied</source> - <translation>已复制PSBT</translation> - </message> - <message> <source>Watch-only balance:</source> <translation>仅观察余额:</translation> </message> @@ -3202,12 +3387,28 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>启用修剪时,如果一个钱包被卸载太久,就必须重新同步整条区块链才能再次加载它。</translation> </message> + <message> + <source>Close all wallets</source> + <translation>关闭所有钱包</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>您确定想要关闭所有钱包吗?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>没有载入钱包。</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>未加载钱包。 +请转到“文件”菜单 > “打开钱包”来加载一个钱包。 +- 或者 -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>创建一个新的钱包</translation> </message> </context> <context> @@ -3280,6 +3481,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>将当前标签页数据导出到文件</translation> </message> <message> + <source>Error</source> + <translation>错误</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>无法从剪贴板解码PSBT(Base64值无效)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>加载交易数据</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>部分签名交易 (*.psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PSBT文件必须小于100MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>无法解码PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>备份钱包</translation> </message> @@ -3323,10 +3548,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>修剪:上次同步钱包的位置已经超出(落后于)现有修剪后数据的范围。你需要进行-reindex(对于已经启用修剪节点,就需要重新下载整个区块链)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>错误:发生了致命的内部错误,详情见 debug.log 文件</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>正在修剪区块存储...</translation> </message> @@ -3339,10 +3560,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%s 开发者</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>无法生成找零地址密钥。 内部密钥池中没有密钥,也无法生成任何密钥。</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>无法锁定数据目录 %s。%s 可能已经在运行。</translation> </message> @@ -3355,6 +3572,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>读取 %s 时发生错误!所有的密钥都可以正确读取,但是交易记录或地址簿数据可能已经丢失或出错。</translation> </message> <message> + <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> + <translation>提供多个洋葱路由绑定地址。对自动创建的洋葱服务用%s</translation> + </message> + <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation>请检查电脑的日期时间设置是否正确!时间错误可能会导致 %s 运行异常。</translation> </message> @@ -3363,6 +3584,18 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>如果你认为%s对你比较有用的话,请对我们进行一些自愿贡献。请访问%s网站来获取有关这个软件的更多信息。</translation> </message> <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase:无法获取sqlit钱包版本:%s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s</source> + <translation>SQLiteDatabase:无法获取应用ID:%s</translation> + </message> + <message> + <source>SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> + <translation>SQLiteDatabase:未知sqlite钱包版本%d。只支持%d版本</translation> + </message> + <message> <source>The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct</source> <translation>区块数据库包含未来的交易,这可能是由本机错误的日期时间引起。若确认本机日期时间正确,请重新建立区块数据库。</translation> </message> @@ -3391,14 +3624,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>警告:我们和其他节点似乎没达成共识!您可能需要升级,或者就是其他节点可能需要升级。</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>最后100个区块中的%d个包含未知的版本号</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>%s 已损坏,抢救失败</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>-maxmempool 最小为%d MB</translation> </message> @@ -3475,6 +3700,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>初始化时重扫描钱包失败</translation> </message> <message> + <source>Failed to verify database</source> + <translation>校验数据库失败</translation> + </message> + <message> <source>Importing...</source> <translation>导入中...</translation> </message> @@ -3503,6 +3732,26 @@ 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>SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <translation>SQLiteDatabase:校验数据库执行语句失败:%s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s</source> + <translation>SQLiteDatabase:无法获取sqlite钱包版本:%s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <translation>SQLiteDatabase:无法准备语句来校验数据库:%s</translation> + </message> + <message> + <source>SQLiteDatabase: Failed to read database verification error: %s</source> + <translation>SQLiteDatabase:无法读取数据库校验错误:%s</translation> + </message> + <message> + <source>SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <translation>SQLiteDatabase:异常应用ID。异常%u,实际%u</translation> + </message> + <message> <source>Specified blocks directory "%s" does not exist.</source> <translation>指定的区块目录"%s"不存在。</translation> </message> @@ -3523,10 +3772,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>正在加载P2P地址...</translation> </message> <message> - <source>Error: Disk space is too low!</source> - <translation>错误:磁盘空间低!</translation> - </message> - <message> <source>Loading banlist...</source> <translation>正在加载黑名单...</translation> </message> @@ -3591,6 +3836,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>错误:监听外部连接失败 (listen函数返回了错误 %s)</translation> </message> <message> + <source>%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> + <translation>%s损坏。请尝试用bitcoin-wallet钱包工具来对其进行急救。或者用一个备份进行还原。</translation> + </message> + <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>无法在不支持“拆分前的密钥池”(pre split keypool)的情况下对“非拆分HD钱包”(non HD split wallet)进行升级。请使用版本号169900,或者压根不要指定版本号。</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>参数 -maxtxfee=<amount>: '%s' 指定了非法的金额 (手续费必须至少达到最小转发费率(minrelay fee) %s 以避免交易卡着发不出去)</translation> </message> @@ -3599,10 +3852,34 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>这笔交易在扣除手续费后的金额太小,以至于无法送出</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>如果这个钱包之前没有正确关闭,而且上一次是被新版的Berkeley DB加载过,就会发生这个错误。如果是这样,请使用上次加载过这个钱包的那个软件。</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>为了在常规选币过程中优先考虑避免“只花出一个地址上的一部分币”(partial spend)这种情况,您最多还需要(在常规手续费之外)付出的交易手续费。</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>交易需要一个找零地址,但是我们无法生成它。请先调用 keypoolrefill 。</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>您需要使用 -reindex 重新构建数据库以回到未修剪模式。这将重新下载整个区块链</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>发生了致命的内部错误,请在debug.log中查看详情</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>没有启用-blockfilterindex,就不能启用-peerblockfilters。</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>磁盘空间太低!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>读取数据库出错,关闭中。</translation> </message> @@ -3615,6 +3892,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>错误: %s 所在的磁盘空间低。</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>错误: 密钥池已被耗尽,请先调用keypoolrefill</translation> + </message> + <message> + <source>Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <translation>手续费率 (%s) 低于最大手续费率设置 (%s)</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> <translation>无效的 -onion 地址: '%s'</translation> </message> @@ -3635,6 +3920,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>-whitebind: '%s' 需要指定一个端口</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>未指定代理服务器。请使用 -proxy=<ip> 或 -proxy=<ip:port> 。</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>修剪模式与 -blockfilterindex 不兼容。</translation> </message> @@ -3709,10 +3998,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>警告:不明的交易规则已经激活(versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>正在销毁钱包中的交易...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>参数 -maxtxfee 被设置得非常高!即使是单笔交易也可能付出如此之大的手续费。</translation> </message> @@ -3725,10 +4010,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>网络版本字符串的总长度 (%i) 超过最大长度 (%i) 了。请减少 uacomment 参数的数目或长度。</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>警告:钱包文件损坏,但数据被救回!原始的钱包文件%s已经重命名为%s并保存到%s目录下 。如果您的账户余额或者交易记录不正确,请使用您的钱包备份文件进行恢复。</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s非常高!</translation> </message> @@ -3773,10 +4054,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>金额不足</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>如果要对“非分离HD钱包(non HD split wallet)”进行升级,就必须先把它升级到支持“未进行分割的密钥池(pre split keypool)”的版本,否则无法进行升级。请使用指定了具体版本号的 -upgradewallet=169900 参数,或者直接使用不指定具体版本号的 -upgradewallet 参数重启钱包。</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>手续费估计失败。而且备用手续费估计(fallbackfee)已被禁用。请再等一些区块,或者通过-fallbackfee参数启用备用手续费估计。</translation> </message> diff --git a/src/qt/locale/bitcoin_zh_HK.ts b/src/qt/locale/bitcoin_zh_HK.ts index 619cd0b768..56875462bc 100644 --- a/src/qt/locale/bitcoin_zh_HK.ts +++ b/src/qt/locale/bitcoin_zh_HK.ts @@ -417,6 +417,9 @@ <name>OverviewPage</name> </context> <context> + <name>PSBTOperationsDialog</name> + </context> +<context> <name>PaymentServer</name> </context> <context> @@ -536,19 +539,7 @@ </context> <context> <name>ReceiveRequestDialog</name> - <message> - <source>Address</source> - <translation>地址</translation> - </message> - <message> - <source>Label</source> - <translation>標記</translation> - </message> - <message> - <source>Wallet</source> - <translation>錢包</translation> - </message> -</context> + </context> <context> <name>RecentRequestsTableModel</name> <message> @@ -645,6 +636,10 @@ <source>Export the data in the current tab to a file</source> <translation>把目前分頁的資料匯出至檔案</translation> </message> + <message> + <source>Error</source> + <translation>錯誤</translation> + </message> </context> <context> <name>bitcoin-core</name> diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts index 27c2b0c71f..2b71aed2f9 100644 --- a/src/qt/locale/bitcoin_zh_TW.ts +++ b/src/qt/locale/bitcoin_zh_TW.ts @@ -3,35 +3,35 @@ <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> - <translation>新增(&N)</translation> + <translation>&新增</translation> </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>複製目前選擇的位址到系統剪貼簿</translation> + <translation>複製目前選擇的地址到系統剪貼簿</translation> </message> <message> <source>&Copy</source> - <translation>複製(&C)</translation> + <translation>&複製</translation> </message> <message> <source>C&lose</source> - <translation>關閉(&L)</translation> + <translation>C&lose</translation> </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> @@ -39,55 +39,56 @@ </message> <message> <source>&Export</source> - <translation>匯出(&E)</translation> + <translation>&匯出</translation> </message> <message> <source>&Delete</source> - <translation>刪掉(&D)</translation> + <translation>&刪除</translation> </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>選取(&H)</translation> + <translation>C&hoose</translation> </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>這些是你要發送過去的 比特幣地址。在發送幣之前,務必要檢查金額和接收地址是否正確。</translation> </message> <message> - <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses.</source> - <translation>這些是您用於接收付款的比特幣位址。 使用接收分頁中的"生成新接收位址"按鈕創建新的位置。</translation> + <source>These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses. +Signing is only possible with addresses of the type 'legacy'.</source> + <translation>這些是您的比特幣接收地址。使用“接收”標籤中的“產生新的接收地址”按鈕產生新的地址。只能使用“傳統”類型的地址進行簽名。</translation> </message> <message> <source>&Copy Address</source> - <translation>複製位址(&C)</translation> + <translation>&複製地址</translation> </message> <message> <source>Copy &Label</source> - <translation>複製標記(&L)</translation> + <translation>複製 &標籤</translation> </message> <message> <source>&Edit</source> - <translation>編輯(&E)</translation> + <translation>&編輯</translation> </message> <message> <source>Export Address List</source> - <translation>匯出位址清單</translation> + <translation>匯出地址清單</translation> </message> <message> <source>Comma separated file (*.csv)</source> @@ -99,7 +100,7 @@ </message> <message> <source>There was an error trying to save the address list to %1. Please try again.</source> - <translation>儲存位址列表到 %1 時發生錯誤。請重試一次。</translation> + <translation>儲存地址清單到 %1 時發生錯誤。請重試一次。</translation> </message> </context> <context> @@ -110,7 +111,7 @@ </message> <message> <source>Address</source> - <translation>位址</translation> + <translation>地址</translation> </message> <message> <source>(no label)</source> @@ -136,6 +137,10 @@ <translation>重複新密碼</translation> </message> <message> + <source>Show passphrase</source> + <translation>顯示密碼</translation> + </message> + <message> <source>Encrypt wallet</source> <translation>加密錢包</translation> </message> @@ -176,10 +181,30 @@ <translation>錢包已加密</translation> </message> <message> + <source>Enter the new passphrase for the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>.</source> + <translation>輸入錢包的新密碼短語。<br/>請使用<b>個或10個以上隨機字符</b>或<b>個8個以上單詞3的密碼。</translation> + </message> + <message> + <source>Enter the old passphrase and new passphrase for the wallet.</source> + <translation>輸入錢包的密碼短語和新密碼短語。</translation> + </message> + <message> <source>Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source> <translation>請記得, 即使將錢包加密, 也不能完全防止因惡意軟體入侵, 而導致位元幣被偷.</translation> </message> <message> + <source>Wallet to be encrypted</source> + <translation>加密錢包</translation> + </message> + <message> + <source>Your wallet is about to be encrypted. </source> + <translation>你的錢包將被加密</translation> + </message> + <message> + <source>Your wallet is now encrypted. </source> + <translation>你的錢包現已被加密</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> @@ -231,7 +256,7 @@ <name>BitcoinGUI</name> <message> <source>Sign &message...</source> - <translation>簽署訊息(&M)...</translation> + <translation>簽名和訊息...</translation> </message> <message> <source>Synchronizing with network...</source> @@ -239,7 +264,7 @@ </message> <message> <source>&Overview</source> - <translation>總覽(&O)</translation> + <translation>&總覽</translation> </message> <message> <source>Show general overview of wallet</source> @@ -247,7 +272,7 @@ </message> <message> <source>&Transactions</source> - <translation>交易(&T)</translation> + <translation>&交易</translation> </message> <message> <source>Browse transaction history</source> @@ -255,17 +280,13 @@ </message> <message> <source>E&xit</source> - <translation>結束(&X)</translation> + <translation>E&xit</translation> </message> <message> <source>Quit application</source> <translation>結束應用程式</translation> </message> <message> - <source>&About %1</source> - <translation>關於%1(&A)</translation> - </message> - <message> <source>Show information about %1</source> <translation>顯示 %1 的相關資訊</translation> </message> @@ -279,7 +300,7 @@ </message> <message> <source>&Options...</source> - <translation>選項(&O)...</translation> + <translation>&選項...</translation> </message> <message> <source>Modify configuration options for %1</source> @@ -287,19 +308,27 @@ </message> <message> <source>&Encrypt Wallet...</source> - <translation>加密錢包(&E)...</translation> + <translation>&加密錢包...</translation> </message> <message> <source>&Backup Wallet...</source> - <translation>備份錢包(&B)...</translation> + <translation>&備份錢包...</translation> </message> <message> <source>&Change Passphrase...</source> - <translation>改變密碼(&C)...</translation> + <translation>&變更密碼短語...</translation> </message> <message> <source>Open &URI...</source> - <translation>開啓 &URI...</translation> + <translation>開啟 &URI...</translation> + </message> + <message> + <source>Create Wallet...</source> + <translation>產生錢包...</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>產生一個新錢包</translation> </message> <message> <source>Wallet:</source> @@ -331,7 +360,7 @@ </message> <message> <source>Send coins to a Bitcoin address</source> - <translation>付錢給一個 Bitcoin 位址</translation> + <translation>發送幣給一個比特幣地址</translation> </message> <message> <source>Backup wallet to another location</source> @@ -343,19 +372,19 @@ </message> <message> <source>&Verify message...</source> - <translation>驗證訊息(&V)...</translation> + <translation>&驗證訊息...</translation> </message> <message> <source>&Send</source> - <translation>付款(&S)</translation> + <translation>&發送</translation> </message> <message> <source>&Receive</source> - <translation>收款(&R)</translation> + <translation>&接收</translation> </message> <message> <source>&Show / Hide</source> - <translation>顯示或隱藏(&S)</translation> + <translation>&顯示或隱藏</translation> </message> <message> <source>Show or hide the main Window</source> @@ -363,27 +392,27 @@ </message> <message> <source>Encrypt the private keys that belong to your wallet</source> - <translation>把錢包中的密鑰加密</translation> + <translation>將錢包中之密鑰加密</translation> </message> <message> <source>Sign messages with your Bitcoin addresses to prove you own them</source> - <translation>用 Bitcoin 位址簽署訊息來證明位址是你的</translation> + <translation>用比特幣地址簽名訊息來證明位址是你的</translation> </message> <message> <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source> - <translation>驗證訊息是用來確定訊息是用指定的 Bitcoin 位址簽署的</translation> + <translation>驗證訊息是用來確定訊息是用指定的比特幣地址簽名的</translation> </message> <message> <source>&File</source> - <translation>檔案(&F)</translation> + <translation>&檔案</translation> </message> <message> <source>&Settings</source> - <translation>設定(&S)</translation> + <translation>&設定</translation> </message> <message> <source>&Help</source> - <translation>說明(&H)</translation> + <translation>&說明</translation> </message> <message> <source>Tabs toolbar</source> @@ -395,15 +424,15 @@ </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>&Command-line options</source> - <translation>命令列選項(&C)</translation> + <translation>&命令行選項</translation> </message> <message numerus="yes"> <source>%n active connection(s) to Bitcoin network</source> @@ -450,12 +479,40 @@ <translation>最新狀態</translation> </message> <message> + <source>&Load PSBT from file...</source> + <translation>從檔案中載入PSBT ...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction</source> + <translation>載入部分簽名的比特幣交易</translation> + </message> + <message> + <source>Load PSBT from clipboard...</source> + <translation>從剪貼簿載入PSBT ...</translation> + </message> + <message> + <source>Load Partially Signed Bitcoin Transaction from clipboard</source> + <translation>從剪貼簿載入部分簽名的比特幣交易</translation> + </message> + <message> + <source>Node window</source> + <translation>節點視窗</translation> + </message> + <message> + <source>Open node debugging and diagnostic console</source> + <translation>開啟節點調試和診斷控制台</translation> + </message> + <message> <source>&Sending addresses</source> - <translation>付款位址(&S)</translation> + <translation>&發送地址</translation> </message> <message> <source>&Receiving addresses</source> - <translation>收款位址(&R)</translation> + <translation>&接收地址</translation> + </message> + <message> + <source>Open a bitcoin: URI</source> + <translation>打開一個比特幣:URI</translation> </message> <message> <source>Open Wallet</source> @@ -474,10 +531,26 @@ <translation>關上錢包</translation> </message> <message> + <source>Close All Wallets...</source> + <translation>關閉所有錢包...</translation> + </message> + <message> + <source>Close all wallets</source> + <translation>關閉所有錢包</translation> + </message> + <message> <source>Show the %1 help message to get a list with possible Bitcoin command-line options</source> <translation>顯示 %1 的說明訊息,來取得可用命令列選項的列表</translation> </message> <message> + <source>&Mask values</source> + <translation>&遮罩值</translation> + </message> + <message> + <source>Mask the values in the Overview tab</source> + <translation>遮蔽“概述”選項卡中的值</translation> + </message> + <message> <source>default wallet</source> <translation>預設錢包</translation> </message> @@ -487,11 +560,11 @@ </message> <message> <source>&Window</source> - <translation>視窗(&W)</translation> + <translation>&視窗</translation> </message> <message> <source>Minimize</source> - <translation>縮小</translation> + <translation>縮到最小</translation> </message> <message> <source>Zoom</source> @@ -503,11 +576,11 @@ </message> <message> <source>%1 client</source> - <translation>%1 客戶端軟體</translation> + <translation>%1 客戶端</translation> </message> <message> <source>Connecting to peers...</source> - <translation>正在跟其他節點連線中...</translation> + <translation>正在跟其他peers連接中...</translation> </message> <message> <source>Catching up...</source> @@ -515,7 +588,7 @@ </message> <message> <source>Error: %1</source> - <translation>错误:%1</translation> + <translation>錯誤:%1</translation> </message> <message> <source>Warning: %1</source> @@ -554,7 +627,7 @@ <message> <source>Address: %1 </source> - <translation>位址: %1 + <translation>地址: %1 </translation> </message> <message> @@ -575,7 +648,7 @@ </message> <message> <source>Private key <b>disabled</b></source> - <translation>私钥<b>禁用</b></translation> + <translation>私鑰<b>禁用</b></translation> </message> <message> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> @@ -586,10 +659,10 @@ <translation>錢包<b>已加密</b>並且<b>上鎖中</b></translation> </message> <message> - <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> - <translation>發生了致命的錯誤。Bitcoin 軟體沒辦法再繼續安全執行,只好結束。</translation> + <source>Original message:</source> + <translation>原始訊息:</translation> </message> -</context> + </context> <context> <name>CoinControlDialog</name> <message> @@ -626,7 +699,7 @@ </message> <message> <source>(un)select all</source> - <translation>全選或全不選</translation> + <translation>(un)全選</translation> </message> <message> <source>Tree mode</source> @@ -646,7 +719,7 @@ </message> <message> <source>Received with address</source> - <translation>收款位址</translation> + <translation>用地址接收</translation> </message> <message> <source>Date</source> @@ -662,7 +735,7 @@ </message> <message> <source>Copy address</source> - <translation>複製位址</translation> + <translation>複製地址</translation> </message> <message> <source>Copy label</source> @@ -702,7 +775,7 @@ </message> <message> <source>Copy dust</source> - <translation>複製零散金額</translation> + <translation>複製灰塵金額</translation> </message> <message> <source>Copy change</source> @@ -722,7 +795,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> @@ -734,7 +807,7 @@ </message> <message> <source>change from %1 (%2)</source> - <translation>找零前是 %1 (%2)</translation> + <translation>找零來自於 %1 (%2)</translation> </message> <message> <source>(change)</source> @@ -743,15 +816,67 @@ </context> <context> <name>CreateWalletActivity</name> - </context> + <message> + <source>Create wallet failed</source> + <translation>創建錢包失敗<br></translation> + </message> + <message> + <source>Create wallet warning</source> + <translation>產生錢包警告:</translation> + </message> +</context> <context> <name>CreateWalletDialog</name> - </context> + <message> + <source>Create Wallet</source> + <translation>新增錢包</translation> + </message> + <message> + <source>Wallet Name</source> + <translation>錢包名稱</translation> + </message> + <message> + <source>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> + <translation>加密錢包。 錢包將使用您選擇的密碼進行加密。</translation> + </message> + <message> + <source>Encrypt Wallet</source> + <translation>加密錢包</translation> + </message> + <message> + <source>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source> + <translation>禁用此錢包的私鑰。取消了私鑰的錢包將沒有私鑰,並且不能有HD種子或匯入的私鑰。這是只能看的錢包的理想選擇。</translation> + </message> + <message> + <source>Disable Private Keys</source> + <translation>禁用私鑰</translation> + </message> + <message> + <source>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source> + <translation>製作一個空白的錢包。空白錢包最初沒有私鑰或腳本。以後可以匯入私鑰和地址,或者可以設定HD種子。</translation> + </message> + <message> + <source>Make Blank Wallet</source> + <translation>製作空白錢包</translation> + </message> + <message> + <source>Use descriptors for scriptPubKey management</source> + <translation>使用descriptors(描述符)進行scriptPubKey管理</translation> + </message> + <message> + <source>Descriptor Wallet</source> + <translation>描述符錢包</translation> + </message> + <message> + <source>Create</source> + <translation>產生</translation> + </message> +</context> <context> <name>EditAddressDialog</name> <message> <source>Edit Address</source> - <translation>編輯位址</translation> + <translation>編輯地址</translation> </message> <message> <source>&Label</source> @@ -759,39 +884,35 @@ </message> <message> <source>The label associated with this address list entry</source> - <translation>跟這個位址簿項目關聯的標記</translation> + <translation>與此地址清單關聯的標籤</translation> </message> <message> <source>The address associated with this address list entry. This can only be modified for sending addresses.</source> - <translation>跟這個位址簿項目關聯的位址。只有付款位址能被修改。</translation> + <translation>跟這個地址清單關聯的地址。只有發送地址能被修改。</translation> </message> <message> <source>&Address</source> - <translation>位址(&A)</translation> + <translation>&地址</translation> </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> - <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> + <translation>輸入的地址 %1 並不是有效的比特幣地址。</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> @@ -859,6 +980,10 @@ <translation>在你按下「好」之後,%1 就會開始下載並處理整個 %4 區塊鏈(大小是 %2GB),也就是從 %3 年 %4 剛剛起步時的最初交易開始。</translation> </message> <message> + <source>Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> + <translation>還原此設置需要重新下載整個區塊鏈。首先下載完整的鏈,然後再修剪它是更快的。禁用某些高級功能。</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>一開始的同步作業非常的耗費資源,並且可能會暴露出之前沒被發現的電腦硬體問題。每次執行 %1 的時候都會繼續先前未完成的下載。</translation> </message> @@ -910,7 +1035,11 @@ <source>(of %n GB needed)</source> <translation><numerusform>(需要 %n GB)</numerusform></translation> </message> - </context> + <message numerus="yes"> + <source>(%n GB needed for full chain)</source> + <translation><numerusform>(完整鏈需要%n GB)</numerusform></translation> + </message> +</context> <context> <name>ModalOverlay</name> <message> @@ -958,6 +1087,10 @@ <translation>隱藏</translation> </message> <message> + <source>Esc</source> + <translation>離開鍵</translation> + </message> + <message> <source>Unknown. Syncing Headers (%1, %2%)...</source> <translation>不明。正在同步前導資料中(%1, %2%)...</translation> </message> @@ -965,6 +1098,10 @@ <context> <name>OpenURIDialog</name> <message> + <source>Open bitcoin URI</source> + <translation>打開比特幣URI</translation> + </message> + <message> <source>URI:</source> <translation>URI:</translation> </message> @@ -972,6 +1109,14 @@ <context> <name>OpenWalletActivity</name> <message> + <source>Open wallet failed</source> + <translation>打開錢包失敗</translation> + </message> + <message> + <source>Open wallet warning</source> + <translation>打開錢包警告</translation> + </message> + <message> <source>default wallet</source> <translation>默认钱包</translation> </message> @@ -1008,17 +1153,13 @@ </message> <message> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> - <translation>代理伺服器的網際網路位址(像是 IPv4 的 127.0.0.1 或 IPv6 的 ::1)</translation> + <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 代理伺服器來連線到 Bitcoin 網路中的 Tor 隱藏服務:</translation> - </message> - <message> <source>Hide the icon from the system tray.</source> <translation>隱藏系統通知區圖示</translation> </message> @@ -1096,7 +1237,7 @@ </message> <message> <source>&Spend unconfirmed change</source> - <translation>可以花還沒確認的零錢(&S)</translation> + <translation>&可以花費還未確認的找零</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> @@ -1151,10 +1292,6 @@ <translation>Tor</translation> </message> <message> - <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</source> - <translation>透過另外的 SOCKS5 代理伺服器來連線到 Bitcoin 網路中的 Tor 隱藏服務。</translation> - </message> - <message> <source>&Window</source> <translation>視窗(&W)</translation> </message> @@ -1195,6 +1332,14 @@ <translation>是否要顯示錢幣控制功能。</translation> </message> <message> + <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> + <translation>通過用於Tor洋蔥服務個別的SOCKS5代理連接到比特幣網路。</translation> + </message> + <message> + <source>Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> + <translation>使用個別的SOCKS&5代理介由Tor onion服務到達peers:</translation> + </message> + <message> <source>&Third party transaction URLs</source> <translation>第三方交易網址連結(&T)</translation> </message> @@ -1224,7 +1369,7 @@ </message> <message> <source>Client restart required to activate changes.</source> - <translation>需要重新啟動客戶端軟體來讓改變生效。</translation> + <translation>需要重新開始客戶端軟體來讓改變生效。</translation> </message> <message> <source>Client will be shut down. Do you want to proceed?</source> @@ -1248,11 +1393,11 @@ </message> <message> <source>This change would require a client restart.</source> - <translation>這項改變需要重新啟動客戶端軟體。</translation> + <translation>這個變更請求重新開始客戶端軟體。</translation> </message> <message> <source>The supplied proxy address is invalid.</source> - <translation>提供的代理伺服器位址無效。</translation> + <translation>提供的代理地址無效。</translation> </message> </context> <context> @@ -1307,7 +1452,7 @@ </message> <message> <source>Your current balance in watch-only addresses</source> - <translation>所有只能看位址的目前餘額</translation> + <translation>所有只能看的地址的當前餘額</translation> </message> <message> <source>Spendable:</source> @@ -1319,15 +1464,114 @@ </message> <message> <source>Unconfirmed transactions to watch-only addresses</source> - <translation>所有只能看位址還沒確認的交易</translation> + <translation>所有只能看的地址還未確認的交易</translation> </message> <message> <source>Mined balance in watch-only addresses that has not yet matured</source> - <translation>所有只能看位址還沒成熟的開採金額</translation> + <translation>所有只能看的地址還沒已熟成的挖出餘額</translation> </message> <message> <source>Current total balance in watch-only addresses</source> - <translation>所有只能看位址的目前全部餘額</translation> + <translation>所有只能看的地址的當前總餘額</translation> + </message> + <message> + <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> + <translation>“總覽”選項卡啟用了隱私模式。要取消遮蔽值,請取消選取 設定->遮蔽值。</translation> + </message> +</context> +<context> + <name>PSBTOperationsDialog</name> + <message> + <source>Dialog</source> + <translation>對話視窗</translation> + </message> + <message> + <source>Sign Tx</source> + <translation>簽名交易</translation> + </message> + <message> + <source>Broadcast Tx</source> + <translation>廣播交易</translation> + </message> + <message> + <source>Copy to Clipboard</source> + <translation>複製到剪貼簿</translation> + </message> + <message> + <source>Save...</source> + <translation>儲存...</translation> + </message> + <message> + <source>Close</source> + <translation>關閉</translation> + </message> + <message> + <source>Could not sign any more inputs.</source> + <translation>無法再簽名 input</translation> + </message> + <message> + <source>Signed transaction successfully. Transaction is ready to broadcast.</source> + <translation>成功簽名交易。交易已準備好廣播。</translation> + </message> + <message> + <source>Unknown error processing transaction.</source> + <translation>處理交易有未知的錯誤</translation> + </message> + <message> + <source>PSBT copied to clipboard.</source> + <translation>PSBT已復製到剪貼簿</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>儲存交易資料</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>部分簽名的交易(二進制)(* .psbt)</translation> + </message> + <message> + <source>PSBT saved to disk.</source> + <translation>PSBT已儲存到磁碟。</translation> + </message> + <message> + <source>Unable to calculate transaction fee or total transaction amount.</source> + <translation>無法計算交易手續費或總交易金額。</translation> + </message> + <message> + <source>Pays transaction fee: </source> + <translation>支付交易手續費:</translation> + </message> + <message> + <source>Total Amount</source> + <translation>總金額</translation> + </message> + <message> + <source>or</source> + <translation>或</translation> + </message> + <message> + <source>Transaction is missing some information about inputs.</source> + <translation>交易缺少有關 input 的一些訊息。</translation> + </message> + <message> + <source>Transaction still needs signature(s).</source> + <translation>交易仍需要簽名。</translation> + </message> + <message> + <source>(But this wallet cannot sign transactions.)</source> + <translation>(但是此錢包無法簽名交易。)</translation> + </message> + <message> + <source>(But this wallet does not have the right keys.)</source> + <translation>(但是這個錢包沒有正確的鑰匙)</translation> + </message> + <message> + <source>Transaction is fully signed and ready for broadcast.</source> + <translation>交易已完全簽名,可以廣播。</translation> + </message> + <message> + <source>Transaction status is unknown.</source> + <translation>交易狀態未知</translation> </message> </context> <context> @@ -1349,12 +1593,24 @@ <translation>字首為 bitcoin:// 不是有效的 URI,請改用 bitcoin: 開頭。</translation> </message> <message> + <source>Cannot process payment request because BIP70 is not supported.</source> + <translation>由於不支援BIP70,因此無法處理付款要求。</translation> + </message> + <message> + <source>Due to widespread security flaws in BIP70 it's strongly recommended that any merchant instructions to switch wallets be ignored.</source> + <translation>由於BIP70中存在廣泛的安全性漏洞,因此強烈建議您忽略任何商戶更換錢包的指示都將被忽略。</translation> + </message> + <message> + <source>If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source> + <translation>如果您收到此錯誤,則應請求商家提供與BIP21相容的URI。</translation> + </message> + <message> <source>Invalid payment address %1</source> - <translation>無效的付款位址 %1</translation> + <translation>無效支付地址 %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 位址!可能是因為 Bitcoin 位址無效,或是 URI 參數格式錯誤。</translation> + <translation>沒辦法解析 URI !可能是因為無效比特幣地址,或是 URI 參數格式錯誤。</translation> </message> <message> <source>Payment request file handling</source> @@ -1396,7 +1652,7 @@ </message> <message> <source>Enter a Bitcoin address (e.g. %1)</source> - <translation>輸入 Bitcoin 位址 (比如說 %1)</translation> + <translation>輸入 比特幣地址 (比如說 %1)</translation> </message> <message> <source>%1 d</source> @@ -1581,10 +1837,6 @@ <translation>區塊鏈</translation> </message> <message> - <source>Current number of blocks</source> - <translation>目前區塊數</translation> - </message> - <message> <source>Memory Pool</source> <translation>記憶體暫存池</translation> </message> @@ -1629,10 +1881,6 @@ <translation>選一個節點來看詳細資訊</translation> </message> <message> - <source>Whitelisted</source> - <translation>列在白名單</translation> - </message> - <message> <source>Direction</source> <translation>方向</translation> </message> @@ -1653,10 +1901,26 @@ <translation>已同步區塊</translation> </message> <message> + <source>The mapped Autonomous System used for diversifying peer selection.</source> + <translation>映射的自治系統,用於使peer選取多樣化。</translation> + </message> + <message> + <source>Mapped AS</source> + <translation>對應 AS</translation> + </message> + <message> <source>User Agent</source> <translation>使用者代理</translation> </message> <message> + <source>Node window</source> + <translation>節點視窗</translation> + </message> + <message> + <source>Current block height</source> + <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> @@ -1669,12 +1933,12 @@ <translation>放大文字</translation> </message> <message> - <source>Services</source> - <translation>服務</translation> + <source>Permissions</source> + <translation>允許</translation> </message> <message> - <source>Ban Score</source> - <translation>惡劣分數</translation> + <source>Services</source> + <translation>服務</translation> </message> <message> <source>Connection Time</source> @@ -1825,14 +2089,6 @@ <translation>出去</translation> </message> <message> - <source>Yes</source> - <translation>是</translation> - </message> - <message> - <source>No</source> - <translation>否</translation> - </message> - <message> <source>Unknown</source> <translation>不明</translation> </message> @@ -1857,7 +2113,7 @@ </message> <message> <source>An optional label to associate with the new receiving address.</source> - <translation>跟新收款位址關聯的標記,可以不填。</translation> + <translation>與新的接收地址關聯的可選的標籤。</translation> </message> <message> <source>Use this form to request payments. All fields are <b>optional</b>.</source> @@ -1868,8 +2124,16 @@ <translation>要求付款的金額,可以不填。不確定金額時可以留白或是填零。</translation> </message> <message> + <source>An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source> + <translation>與新的接收地址相關聯的可選的標籤(您用於標識收據)。它也附在支付支付請求上。</translation> + </message> + <message> + <source>An optional message that is attached to the payment request and may be displayed to the sender.</source> + <translation>附加在支付請求上的可選的訊息,可以顯示給發送者。</translation> + </message> + <message> <source>&Create new receiving address</source> - <translation>&生成新的接收位址</translation> + <translation>&產生新的接收地址</translation> </message> <message> <source>Clear all fields of the form.</source> @@ -1881,11 +2145,11 @@ </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> + <translation>使用原生的隔離見證地址(也叫做 Bech32 或 BIP-173)可以減少日後的交易手續費,並能更好地防止輸入錯誤,不過會跟舊版的錢包軟體不支援。如果沒有勾選的話,會改產生與舊版錢包軟體相容的地址。</translation> </message> <message> <source>Generate native segwit (Bech32) address</source> - <translation>產生 segwit 原生位址(Bech32)</translation> + <translation>產生原生隔離見證(Bech32)地址</translation> </message> <message> <source>Requested payments history</source> @@ -1923,56 +2187,56 @@ <source>Copy amount</source> <translation>複製金額</translation> </message> -</context> -<context> - <name>ReceiveRequestDialog</name> <message> - <source>QR Code</source> - <translation>QR Code</translation> + <source>Could not unlock wallet.</source> + <translation>沒辦法把錢包解鎖。</translation> </message> + </context> +<context> + <name>ReceiveRequestDialog</name> <message> - <source>Copy &URI</source> - <translation>複製 &URI</translation> + <source>Request payment to ...</source> + <translation>請求付款給...</translation> </message> <message> - <source>Copy &Address</source> - <translation>複製位址(&A)</translation> + <source>Address:</source> + <translation>地址:</translation> </message> <message> - <source>&Save Image...</source> - <translation>儲存圖片(&S)...</translation> + <source>Amount:</source> + <translation>金額:</translation> </message> <message> - <source>Request payment to %1</source> - <translation>付款給 %1 的要求</translation> + <source>Label:</source> + <translation>標記:</translation> </message> <message> - <source>Payment information</source> - <translation>付款資訊</translation> + <source>Message:</source> + <translation>訊息:</translation> </message> <message> - <source>URI</source> - <translation>URI</translation> + <source>Wallet:</source> + <translation>錢包:</translation> </message> <message> - <source>Address</source> - <translation>位址</translation> + <source>Copy &URI</source> + <translation>複製 &URI</translation> </message> <message> - <source>Amount</source> - <translation>金額</translation> + <source>Copy &Address</source> + <translation>複製 &地址</translation> </message> <message> - <source>Label</source> - <translation>標記:</translation> + <source>&Save Image...</source> + <translation>儲存圖片(&S)...</translation> </message> <message> - <source>Message</source> - <translation>訊息</translation> + <source>Request payment to %1</source> + <translation>付款給 %1 的要求</translation> </message> <message> - <source>Wallet</source> - <translation>錢包</translation> + <source>Payment information</source> + <translation>付款資訊</translation> </message> </context> <context> @@ -2054,7 +2318,7 @@ </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> @@ -2121,6 +2385,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>零散錢:</translation> </message> <message> + <source>Hide transaction fee settings</source> + <translation>隱藏交易手續費設定</translation> + </message> + <message> <source>When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source> <translation>当交易量小于可用区块空间时,矿工和中继节点可能会执行最低手续费率限制。按照这个最低费率来支付手续费也是可以的,但请注意,一旦交易需求超出比特币网络能处理的限度,你的交易可能永远也无法确认。</translation> </message> @@ -2189,6 +2457,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%1 (%2 個區塊)</translation> </message> <message> + <source>Cr&eate Unsigned</source> + <translation>Cr&eate未簽名</translation> + </message> + <message> <source> from wallet '%1'</source> <translation>從錢包 %1</translation> </message> @@ -2201,10 +2473,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%1 給 %2</translation> </message> <message> + <source>Do you want to draft this transaction?</source> + <translation>您要草擬此交易嗎?</translation> + </message> + <message> <source>Are you sure you want to send?</source> <translation>你確定要付錢出去嗎?</translation> </message> <message> + <source>Create Unsigned</source> + <translation>產生未簽名</translation> + </message> + <message> + <source>Save Transaction Data</source> + <translation>儲存交易資料</translation> + </message> + <message> + <source>Partially Signed Transaction (Binary) (*.psbt)</source> + <translation>部分簽名的交易(二進制)(* .psbt)</translation> + </message> + <message> + <source>PSBT saved</source> + <translation>PSBT已儲存</translation> + </message> + <message> <source>or</source> <translation>或</translation> </message> @@ -2237,8 +2529,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>確認付款金額</translation> </message> <message> + <source>Confirm transaction proposal</source> + <translation>確認交易建議</translation> + </message> + <message> + <source>Send</source> + <translation>發</translation> + </message> + <message> + <source>Watch-only balance:</source> + <translation>只能看餘額:</translation> + </message> + <message> <source>The recipient address is not valid. Please recheck.</source> - <translation>收款位址無效。請再檢查看看。</translation> + <translation>接受者地址無效。請再檢查看看。</translation> </message> <message> <source>The amount to pay must be larger than 0.</source> @@ -2254,7 +2558,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Duplicate address found: addresses should only be used once each.</source> - <translation>發現有重複的位址: 每個位址只能出現一次。</translation> + <translation>發現有重複的地址: 每個地址只能出現一次。</translation> </message> <message> <source>Transaction creation failed!</source> @@ -2274,19 +2578,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Warning: Invalid Bitcoin address</source> - <translation>警告: Bitcoin 位址無效</translation> + <translation>警告: 比特幣地址無效</translation> </message> <message> <source>Warning: Unknown change address</source> - <translation>警告: 不明的找零位址</translation> + <translation>警告: 未知的找零地址</translation> </message> <message> <source>Confirm custom change address</source> - <translation>自定找零位址確認</translation> + <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> + <translation>選擇的找零地址並不屬於這個錢包。部份或是全部的錢會被送到這個地址去。你確定嗎?</translation> </message> <message> <source>(no label)</source> @@ -2309,11 +2613,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Choose previously used address</source> - <translation>選擇先前使用過的位址</translation> + <translation>選擇先前使用過的地址</translation> </message> <message> <source>The Bitcoin address to send the payment to</source> - <translation>接收付款的 Bitcoin 位址</translation> + <translation>將支付發送到的比特幣地址給</translation> </message> <message> <source>Alt+A</source> @@ -2321,7 +2625,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Paste address from clipboard</source> - <translation>貼上剪貼簿裡的位址</translation> + <translation>貼上剪貼簿裡的地址</translation> </message> <message> <source>Alt+P</source> @@ -2332,6 +2636,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>刪掉這個項目</translation> </message> <message> + <source>The amount to send in the selected unit</source> + <translation>以所選單位發送的金額</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>手續費會從要付款出去的金額中扣掉。因此收款人會收到比輸入的金額還要少的 bitcoin。如果有多個收款人的話,手續費會平均分配來扣除。</translation> </message> @@ -2357,7 +2665,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Enter a label for this address to add it to the list of used addresses</source> - <translation>請輸入這個位址的標記,來把它加進去已使用過位址的清單。</translation> + <translation>請輸入這個地址的標籤,來把它加進去已使用過地址清單。</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> @@ -2395,15 +2703,15 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </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>你可以用自己的位址簽署訊息或合約,來證明你可以從該位址收款。但是請小心,不要簽署語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽署的手法來冒充是你。只有在語句中的細節你都同意時才簽署。</translation> + <translation>您可以使用您的地址簽名訊息/協議,以證明您可以接收發送給他們的比特幣。但是請小心,不要簽名語意含糊不清,或隨機產生的內容,因為釣魚式詐騙可能會用騙你簽名的手法來冒充是你。只有簽名您同意的詳細內容。</translation> </message> <message> <source>The Bitcoin address to sign the message with</source> - <translation>用來簽署訊息的 Bitcoin 位址</translation> + <translation>用來簽名訊息的 比特幣地址</translation> </message> <message> <source>Choose previously used address</source> - <translation>選擇先前使用過的位址</translation> + <translation>選擇先前使用過的地址</translation> </message> <message> <source>Alt+A</source> @@ -2411,7 +2719,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Paste address from clipboard</source> - <translation>貼上剪貼簿裡的位址</translation> + <translation>貼上剪貼簿裡的地址</translation> </message> <message> <source>Alt+P</source> @@ -2431,7 +2739,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Sign the message to prove you own this Bitcoin address</source> - <translation>簽署這個訊息來證明這個 Bitcoin 位址是你的</translation> + <translation>簽名這個訊息來證明這個比特幣地址是你的</translation> </message> <message> <source>Sign &Message</source> @@ -2451,15 +2759,23 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </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>請在下面輸入收款人的位址,訊息(請確定完整複製了所包含的換行,空格,跳位符號等等),以及簽章,來驗證這個訊息。請小心,除了訊息內容以外,不要對簽章本身過度解讀,以避免被用「中間人攻擊法」詐騙。請注意,通過驗證的簽章只能證明簽章人確實可以從該位址收款,不能證明任何交易中的付款人身份!</translation> + <translation>請在下面輸入收款人的地址,訊息(請確定完整複製了所包含的換行、空格、tabs...等),以及簽名,來驗證這個訊息。請小心,除了訊息內容以外,不要對簽名本身過度解讀,以避免被用「中間人攻擊法」詐騙。請注意,通過驗證的簽名只能證明簽名人確實可以從該地址收款,不能證明任何交易中的付款人身份!</translation> </message> <message> <source>The Bitcoin address the message was signed with</source> - <translation>簽署這個訊息的 Bitcoin 位址</translation> + <translation>簽名這個訊息的 比特幣地址</translation> + </message> + <message> + <source>The signed message to verify</source> + <translation>簽名訊息進行驗證</translation> + </message> + <message> + <source>The signature given when the message was signed</source> + <translation>簽名訊息時給出的簽名</translation> </message> <message> <source>Verify the message to ensure it was signed with the specified Bitcoin address</source> - <translation>驗證這個訊息來確定是用指定的 Bitcoin 位址簽署的</translation> + <translation>驗證這個訊息來確定是用指定的比特幣地址簽名的</translation> </message> <message> <source>Verify &Message</source> @@ -2475,23 +2791,27 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>The entered address is invalid.</source> - <translation>輸入的位址無效。</translation> + <translation>輸入的地址無效。</translation> </message> <message> <source>Please check the address and try again.</source> - <translation>請檢查位址是否正確後再試一次。</translation> + <translation>請檢查地址是否正確後再試一次。</translation> </message> <message> <source>The entered address does not refer to a key.</source> - <translation>輸入的位址沒有對應到你的任何密鑰。</translation> + <translation>輸入的地址沒有對應到你的任何鑰匙。</translation> </message> <message> <source>Wallet unlock was cancelled.</source> <translation>錢包解鎖已取消。</translation> </message> <message> + <source>No error</source> + <translation>沒有錯誤</translation> + </message> + <message> <source>Private key for the entered address is not available.</source> - <translation>沒有對應輸入位址的密鑰。</translation> + <translation>沒有對應輸入地址的私鑰。</translation> </message> <message> <source>Message signing failed.</source> @@ -2597,7 +2917,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>own address</source> - <translation>自己的位址</translation> + <translation>自己的地址</translation> </message> <message> <source>watch-only</source> @@ -2664,6 +2984,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>輸出索引</translation> </message> <message> + <source> (Certificate was not verified)</source> + <translation>(證書未驗證)</translation> + </message> + <message> <source>Merchant</source> <translation>商家</translation> </message> @@ -2803,7 +3127,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Whether or not a watch-only address is involved in this transaction.</source> - <translation>不論如何有一個只能觀看的地只有參與這次的交易</translation> + <translation>此交易是否涉及監視地址。</translation> </message> <message> <source>User-defined intent/purpose of the transaction.</source> @@ -2866,7 +3190,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Enter address, transaction id, or label to search</source> - <translation>請輸入要搜尋的位址、交易識別碼、或是標記</translation> + <translation>請輸入要搜尋的地址、交易 ID、或是標記標籤</translation> </message> <message> <source>Min amount</source> @@ -2882,7 +3206,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Copy address</source> - <translation>複製位址</translation> + <translation>複製地址</translation> </message> <message> <source>Copy label</source> @@ -2942,7 +3266,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Address</source> - <translation>位址</translation> + <translation>地址</translation> </message> <message> <source>ID</source> @@ -2990,12 +3314,28 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <source>Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <translation>關上錢包太久的話且修剪模式又有開啟的話,可能會造成日後需要重新同步整個區塊鏈。</translation> </message> + <message> + <source>Close all wallets</source> + <translation>關閉所有錢包</translation> + </message> + <message> + <source>Are you sure you wish to close all wallets?</source> + <translation>您確定要關閉所有錢包嗎?</translation> + </message> </context> <context> <name>WalletFrame</name> <message> - <source>No wallet has been loaded.</source> - <translation>沒有載入錢包。</translation> + <source>No wallet has been loaded. +Go to File > Open Wallet to load a wallet. +- OR -</source> + <translation>尚未載入任何錢包。 +轉到檔案 > 開啟錢包以載入錢包. +- OR -</translation> + </message> + <message> + <source>Create a new wallet</source> + <translation>創建一個新錢包</translation> </message> </context> <context> @@ -3017,6 +3357,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>想要提高手續費嗎?</translation> </message> <message> + <source>Do you want to draft a transaction with fee increase?</source> + <translation>您想通過增加手續費草擬交易嗎?</translation> + </message> + <message> <source>Current fee:</source> <translation>目前費用:</translation> </message> @@ -3033,6 +3377,14 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>確認手續費提升</translation> </message> <message> + <source>Can't draft transaction.</source> + <translation>無法草擬交易。</translation> + </message> + <message> + <source>PSBT copied</source> + <translation>PSBT已復制</translation> + </message> + <message> <source>Can't sign transaction.</source> <translation>沒辦法簽署交易。</translation> </message> @@ -3056,6 +3408,30 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>將目前分頁的資料匯出存成檔案</translation> </message> <message> + <source>Error</source> + <translation>錯誤</translation> + </message> + <message> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation>無法從剪貼板解碼PSBT(無效的base64)</translation> + </message> + <message> + <source>Load Transaction Data</source> + <translation>載入交易資料</translation> + </message> + <message> + <source>Partially Signed Transaction (*.psbt)</source> + <translation>簽名部分的交易(* .psbt)</translation> + </message> + <message> + <source>PSBT file must be smaller than 100 MiB</source> + <translation>PSBT檔案必須小於100 MiB</translation> + </message> + <message> + <source>Unable to decode PSBT</source> + <translation>無法解碼PSBT</translation> + </message> + <message> <source>Backup Wallet</source> <translation>備份錢包</translation> </message> @@ -3099,10 +3475,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>修剪模式:錢包的最後同步狀態是在被修剪掉的區塊資料中。你需要用 -reindex 參數執行(會重新下載整個區塊鏈)</translation> </message> <message> - <source>Error: A fatal internal error occurred, see debug.log for details</source> - <translation>錯誤: 發生了致命的內部錯誤,詳情請看 debug.log</translation> - </message> - <message> <source>Pruning blockstore...</source> <translation>正在修剪區塊資料庫中...</translation> </message> @@ -3115,10 +3487,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>%s 開發人員</translation> </message> <message> - <source>Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.</source> - <translation>无法生成找零地址密钥。 内部密钥池中没有密钥,也无法生成任何密钥。</translation> - </message> - <message> <source>Cannot obtain a lock on data directory %s. %s is probably already running.</source> <translation>沒辦法鎖定資料目錄 %s。%s 可能已經在執行了。</translation> </message> @@ -3128,7 +3496,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> - <translation>讀取錢包檔 %s 時發生錯誤!所有的密鑰都正確讀取了,但是交易資料或位址簿資料可能會缺少或不正確。</translation> + <translation>讀取錢包檔 %s 時發生錯誤!所有的鑰匙都正確讀取了,但是交易資料或地址簿資料可能會缺少或不正確。</translation> </message> <message> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> @@ -3167,20 +3535,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>警告: 我們和某些連線的節點對於區塊鏈結的決定不同!你可能需要升級,或是需要等其它的節點升級。</translation> </message> <message> - <source>%d of last 100 blocks have unexpected version</source> - <translation>最近的 100 個區塊中有 %d 個意料之外的區塊版本</translation> - </message> - <message> - <source>%s corrupt, salvage failed</source> - <translation>錢包檔 %s 壞掉了,搶救失敗</translation> - </message> - <message> <source>-maxmempool must be at least %d MB</source> <translation>參數 -maxmempool 至少要給 %d 百萬位元組(MB)</translation> </message> <message> <source>Cannot resolve -%s address: '%s'</source> - <translation>沒辦法解析 -%s 參數指定的位址: '%s'</translation> + <translation>沒辦法解析 -%s 參數指定的地址: '%s'</translation> </message> <message> <source>Change index out of range</source> @@ -3276,7 +3636,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Unknown address type '%s'</source> - <translation>不明的位址類型 '%s'</translation> + <translation>未知的地址類型 '%s'</translation> </message> <message> <source>Unknown change type '%s'</source> @@ -3288,11 +3648,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Loading P2P addresses...</source> - <translation>正在載入 P2P 位址資料...</translation> - </message> - <message> - <source>Error: Disk space is too low!</source> - <translation>錯誤: 磁碟空間很少!</translation> + <translation>正在載入 P2P 地址資料...</translation> </message> <message> <source>Loading banlist...</source> @@ -3359,6 +3715,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>錯誤: 聽候外來連線失敗(回傳錯誤 %s)</translation> </message> <message> + <source>Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.</source> + <translation>如果不升級以支援預拆分keypool,則無法升級非HD拆分錢包。請使用169900版本或沒有版本。</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>-maxtxfee=<amount>: '%s' 的金額無效 (必須大於最低轉發手續費 %s 以避免交易無法確認)</translation> </message> @@ -3367,10 +3727,34 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>扣除手續費後的交易金額太少而不能傳送</translation> </message> <message> + <source>This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> + <translation>如果未完全關閉該錢包,並且最後一次使用具有較新版本的Berkeley DB的構建載入了此錢包,則可能會發生此錯誤。如果是這樣,請使用最後載入該錢包的軟體</translation> + </message> + <message> + <source>This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> + <translation>這是您支付的最高交易手續費(除了正常手續費外),優先於避免部分花費而不是定期選取幣。</translation> + </message> + <message> + <source>Transaction needs a change address, but we can't generate it. Please call keypoolrefill first.</source> + <translation>交易需要變更地址,但我們無法產生它。請先呼叫keypoolrefill。</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>回到非修剪的模式需要用 -reindex 參數來重建資料庫。這會導致重新下載整個區塊鏈。</translation> </message> <message> + <source>A fatal internal error occurred, see debug.log for details</source> + <translation>發生致命的內部錯誤,有關詳細細節,請參見debug.log</translation> + </message> + <message> + <source>Cannot set -peerblockfilters without -blockfilterindex.</source> + <translation>在沒有設定-blockfilterindex 則無法使用 -peerblockfilters</translation> + </message> + <message> + <source>Disk space is too low!</source> + <translation>硬碟空間太小!</translation> + </message> + <message> <source>Error reading from database, shutting down.</source> <translation>讀取資料庫時發生錯誤,要關閉了。</translation> </message> @@ -3383,12 +3767,16 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>错误: %s 所在的磁盘空间低。</translation> </message> <message> + <source>Error: Keypool ran out, please call keypoolrefill first</source> + <translation>錯誤:keypool已用完,請先重新呼叫keypoolrefill</translation> + </message> + <message> <source>Invalid -onion address or hostname: '%s'</source> - <translation>無效的 -onion 位址或主機名稱: '%s'</translation> + <translation>無效的 -onion 地址或主機名稱: '%s'</translation> </message> <message> <source>Invalid -proxy address or hostname: '%s'</source> - <translation>無效的 -proxy 位址或主機名稱: '%s'</translation> + <translation>無效的 -proxy 地址或主機名稱: '%s'</translation> </message> <message> <source>Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> @@ -3403,6 +3791,10 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>指定 -whitebind 時必須包含通訊埠: '%s'</translation> </message> <message> + <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> + <translation>未指定代理伺服器。使用-proxy = <ip>或-proxy = <ip:port>。</translation> + </message> + <message> <source>Prune mode is incompatible with -blockfilterindex.</source> <translation>修剪模式與 -blockfilterindex不相容。</translation> </message> @@ -3458,7 +3850,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Unable to create the PID file '%s': %s</source> - <translation>无法创建PID文件'%s': %s</translation> + <translation>無法創建PID文件'%s': %s</translation> </message> <message> <source>Unable to generate initial keys</source> @@ -3477,10 +3869,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>警告: 不明的交易規則被啟用了(versionbit %i)</translation> </message> <message> - <source>Zapping all transactions from wallet...</source> - <translation>正在砍掉錢包中的所有交易...</translation> - </message> - <message> <source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <translation>參數 -maxtxfee 設定了很高的金額!這可是你一次交易就有可能付出的最高手續費。</translation> </message> @@ -3493,10 +3881,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>網路版本字串的總長度(%i)超過最大長度(%i)了。請減少 uacomment 參數的數目或長度。</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>警告: 錢包檔壞掉,但資料被救回來了!原來的檔案 %s 改儲存為 %s,在目錄 %s 下。 如果餘額或交易資料有誤的話,你應該要從備份資料復原回來。</translation> - </message> - <message> <source>%s is set very high!</source> <translation>%s 的設定值異常大!</translation> </message> @@ -3530,7 +3914,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p </message> <message> <source>Transaction must have at least one recipient</source> - <translation>交易必須至少要有一個收款人</translation> + <translation>交易必須至少有一個收款人</translation> </message> <message> <source>Unknown network specified in -onlynet: '%s'</source> @@ -3541,10 +3925,6 @@ Note: Since the fee is calculated on a per-byte basis, a fee of "100 satoshis p <translation>累積金額不足</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>無法將一個非 HD 分支錢包升級成不支援預先分支密鑰池的 HD 分支錢包版本。請用 -upgradewallet=169900 參數或是不指定版本的 -upgradewallet 參數來升級錢包。</translation> - </message> - <message> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation>計算預估手續費失敗了,也沒有備用手續費(fallbackfee)可用。請再多等待幾個區塊,或是啟用 -fallbackfee 參數。</translation> </message> diff --git a/src/qt/locale/bitcoin_zu.ts b/src/qt/locale/bitcoin_zu.ts new file mode 100644 index 0000000000..0ff40282a3 --- /dev/null +++ b/src/qt/locale/bitcoin_zu.ts @@ -0,0 +1,282 @@ +<TS language="zu" version="2.1"> +<context> + <name>AddressBookPage</name> + <message> + <source>Right-click to edit address or label</source> + <translation>Qhafaza kwesokudla ukuze uhlele ikheli noma ilebula</translation> + </message> + <message> + <source>Create a new address</source> + <translation>Dala ikheli elisha</translation> + </message> + <message> + <source>Copy the currently selected address to the system clipboard</source> + <translation>Kopisha ikheli elikhethwe njengamanje ebhodini lokunameka lesistimu</translation> + </message> + <message> + <source>Delete the currently selected address from the list</source> + <translation>Susa ikheli elikhethwe njengamanje ohlwini</translation> + </message> + <message> + <source>Enter address or label to search</source> + <translation>Faka ikheli noma ilebula ukusesha</translation> + </message> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Khiphela idatha kuthebhu yamanje kufayela</translation> + </message> + <message> + <source>Choose the address to send coins to</source> + <translation>Khetha ikheli ozothumela kulo izinhlamvu zemali</translation> + </message> + <message> + <source>Choose the address to receive coins with</source> + <translation>Khetha ikheli ukuthola izinhlamvu zemali nge</translation> + </message> + <message> + <source>Sending addresses</source> + <translation>Kuthunyelwa amakheli</translation> + </message> + <message> + <source>Receiving addresses</source> + <translation>Ukuthola amakheli</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>Lawa amakheli akho e-Bitcoin okuthumela izinkokhelo. Njalo hlola inani nekheli elitholwayo ngaphambi kokuthumela izinhlamvu zemali.</translation> + </message> + <message> + <source>Export Address List</source> + <translation>Thumela Ikheli Langaphandle</translation> + </message> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Ifayela elihlukaniswe ngokhefana (* .csv)</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Ukuthekelisa kwehlulekile</translation> + </message> + </context> +<context> + <name>AddressTableModel</name> + <message> + <source>Label</source> + <translation>Ilebuli</translation> + </message> + <message> + <source>Address</source> + <translation>Ikheli</translation> + </message> + <message> + <source>(no label)</source> + <translation>(akukho ilebula)</translation> + </message> +</context> +<context> + <name>AskPassphraseDialog</name> + <message> + <source>Passphrase Dialog</source> + <translation>I-Passphrase Dialog</translation> + </message> + <message> + <source>Enter passphrase</source> + <translation>Faka umushwana wokungena</translation> + </message> + <message> + <source>New passphrase</source> + <translation>Umushwana omusha wokungena</translation> + </message> + <message> + <source>Repeat new passphrase</source> + <translation>Phinda umushwana omusha wokungena</translation> + </message> + <message> + <source>Show passphrase</source> + <translation>Khombisa umushwana wokungena</translation> + </message> + <message> + <source>Encrypt wallet</source> + <translation>Bethela isikhwama</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to unlock the wallet.</source> + <translation>Lokhu kusebenza kudinga umushwana wakho wokungena wesikhwama ukuvula isikhwama.</translation> + </message> + <message> + <source>Unlock wallet</source> + <translation>Vula isikhwama semali</translation> + </message> + <message> + <source>This operation needs your wallet passphrase to decrypt the wallet.</source> + <translation>Lo msebenzi udinga umushwana wakho wokungena wesikhwama ukukhipha isikhwama esikhwameni.</translation> + </message> + <message> + <source>Decrypt wallet</source> + <translation>Ukhiphe isikhwama semali</translation> + </message> + <message> + <source>Change passphrase</source> + <translation>Shintsha umushwana wokungena</translation> + </message> + <message> + <source>Confirm wallet encryption</source> + <translation>Qinisekisa ukubethelwa kwe-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>Isexwayiso: Uma ubhala ngemfihlo isikhwama sakho futhi ulahlekelwe umushwana wakho wokungena, uzokwazi +Lahla YONKE IBITCOIN YAKHO!</translation> + </message> + <message> + <source>Are you sure you wish to encrypt your wallet?</source> + <translation>Uqinisekile ukuthi ufisa ukubhala ngemfihlo isikhwama sakho?</translation> + </message> + <message> + <source>Wallet encrypted</source> + <translation>Kufakwe i-Wallet</translation> + </message> + </context> +<context> + <name>BanTableModel</name> + </context> +<context> + <name>BitcoinGUI</name> + </context> +<context> + <name>CoinControlDialog</name> + </context> +<context> + <name>CreateWalletActivity</name> + </context> +<context> + <name>CreateWalletDialog</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>OpenWalletActivity</name> + </context> +<context> + <name>OptionsDialog</name> + </context> +<context> + <name>OverviewPage</name> + </context> +<context> + <name>PSBTOperationsDialog</name> + </context> +<context> + <name>PaymentServer</name> + </context> +<context> + <name>PeerTableModel</name> + </context> +<context> + <name>QObject</name> + </context> +<context> + <name>QRImageWidget</name> + </context> +<context> + <name>RPCConsole</name> + </context> +<context> + <name>ReceiveCoinsDialog</name> + </context> +<context> + <name>ReceiveRequestDialog</name> + </context> +<context> + <name>RecentRequestsTableModel</name> + <message> + <source>Label</source> + <translation>Ilebuli</translation> + </message> + </context> +<context> + <name>SendCoinsDialog</name> + </context> +<context> + <name>SendCoinsEntry</name> + </context> +<context> + <name>ShutdownWindow</name> + </context> +<context> + <name>SignVerifyMessageDialog</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>Ilebuli</translation> + </message> + </context> +<context> + <name>TransactionView</name> + <message> + <source>Comma separated file (*.csv)</source> + <translation>Ifayela elihlukaniswe ngokhefana (* .csv)</translation> + </message> + <message> + <source>Label</source> + <translation>Ilebuli</translation> + </message> + <message> + <source>Address</source> + <translation>Ikheli</translation> + </message> + <message> + <source>Exporting Failed</source> + <translation>Ukuthekelisa kwehlulekile</translation> + </message> + </context> +<context> + <name>UnitDisplayStatusBarControl</name> + </context> +<context> + <name>WalletController</name> + </context> +<context> + <name>WalletFrame</name> + </context> +<context> + <name>WalletModel</name> + </context> +<context> + <name>WalletView</name> + <message> + <source>Export the data in the current tab to a file</source> + <translation>Khipha idatha kuthebhu yamanje kufayela</translation> + </message> + </context> +<context> + <name>bitcoin-core</name> + </context> +</TS>
\ No newline at end of file diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h index 7b07777641..1d8af5cbf6 100644 --- a/src/qt/modaloverlay.h +++ b/src/qt/modaloverlay.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp index 4b91c19761..b097ef080c 100644 --- a/src/qt/notificator.cpp +++ b/src/qt/notificator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,12 +17,7 @@ #include <stdint.h> #include <QtDBus> #endif -// Include ApplicationServices.h after QtDbus to avoid redefinition of check(). -// This affects at least OSX 10.6. See /usr/include/AssertMacros.h for details. -// Note: This could also be worked around using: -// #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0 #ifdef Q_OS_MAC -#include <ApplicationServices/ApplicationServices.h> #include <qt/macnotificationhandler.h> #endif @@ -71,7 +66,7 @@ Notificator::~Notificator() #ifdef USE_DBUS -// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html +// Loosely based on https://www.qtcentre.org/archive/index.php/t-25879.html class FreedesktopImage { public: diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp index 9a3d43c2a6..10bf82d532 100644 --- a/src/qt/openuridialog.cpp +++ b/src/qt/openuridialog.cpp @@ -11,7 +11,7 @@ #include <QUrl> OpenURIDialog::OpenURIDialog(QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::OpenURIDialog) { ui->setupUi(this); diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h index 667af2ec75..efe4b86f37 100644 --- a/src/qt/openuridialog.h +++ b/src/qt/openuridialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index ae6aeb7709..7b8d7871ec 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -24,11 +24,12 @@ #include <QIntValidator> #include <QLocale> #include <QMessageBox> +#include <QSettings> #include <QSystemTrayIcon> #include <QTimer> OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::OptionsDialog), model(nullptr), mapper(nullptr) @@ -50,6 +51,13 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : #ifndef USE_UPNP ui->mapPortUpnp->setEnabled(false); #endif +#ifndef USE_NATPMP + ui->mapPortNatpmp->setEnabled(false); +#endif + connect(this, &QDialog::accepted, [this](){ + QSettings settings; + model->node().mapPort(settings.value("fUseUPnP").toBool(), settings.value("fUseNatpmp").toBool()); + }); ui->proxyIp->setEnabled(false); ui->proxyPort->setEnabled(false); @@ -130,8 +138,8 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) : connect(ui->proxyPortTor, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState); if (!QSystemTrayIcon::isSystemTrayAvailable()) { - ui->hideTrayIcon->setChecked(true); - ui->hideTrayIcon->setEnabled(false); + ui->showTrayIcon->setChecked(false); + ui->showTrayIcon->setEnabled(false); ui->minimizeToTray->setChecked(false); ui->minimizeToTray->setEnabled(false); } @@ -214,6 +222,7 @@ void OptionsDialog::setMapper() /* Network */ mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP); + mapper->addMapping(ui->mapPortNatpmp, OptionsModel::MapPortNatpmp); mapper->addMapping(ui->allowIncoming, OptionsModel::Listen); mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse); @@ -227,7 +236,7 @@ void OptionsDialog::setMapper() /* Window */ #ifndef Q_OS_MAC if (QSystemTrayIcon::isSystemTrayAvailable()) { - mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon); + mapper->addMapping(ui->showTrayIcon, OptionsModel::ShowTrayIcon); mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray); } mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose); @@ -286,17 +295,14 @@ void OptionsDialog::on_cancelButton_clicked() reject(); } -void OptionsDialog::on_hideTrayIcon_stateChanged(int fState) +void OptionsDialog::on_showTrayIcon_stateChanged(int state) { - if(fState) - { + if (state == Qt::Checked) { + ui->minimizeToTray->setEnabled(true); + } else { ui->minimizeToTray->setChecked(false); ui->minimizeToTray->setEnabled(false); } - else - { - ui->minimizeToTray->setEnabled(true); - } } void OptionsDialog::togglePruneWarning(bool enabled) diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 568c8b6fd0..1cc96035c6 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -57,7 +57,7 @@ private Q_SLOTS: void on_okButton_clicked(); void on_cancelButton_clicked(); - void on_hideTrayIcon_stateChanged(int fState); + void on_showTrayIcon_stateChanged(int state); void togglePruneWarning(bool enabled); void showRestartWarning(bool fPersistent = false); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 7e089b4f95..1e0391a35c 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -13,11 +13,12 @@ #include <qt/guiutil.h> #include <interfaces/node.h> -#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS +#include <mapport.h> #include <net.h> #include <netbase.h> -#include <txdb.h> // for -dbcache defaults +#include <txdb.h> // for -dbcache defaults #include <util/string.h> +#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS #include <QDebug> #include <QSettings> @@ -54,14 +55,15 @@ void OptionsModel::Init(bool resetSettings) // These are Qt-only settings: // Window - if (!settings.contains("fHideTrayIcon")) + if (!settings.contains("fHideTrayIcon")) { settings.setValue("fHideTrayIcon", false); - fHideTrayIcon = settings.value("fHideTrayIcon").toBool(); - Q_EMIT hideTrayIconChanged(fHideTrayIcon); + } + m_show_tray_icon = !settings.value("fHideTrayIcon").toBool(); + Q_EMIT showTrayIconChanged(m_show_tray_icon); if (!settings.contains("fMinimizeToTray")) settings.setValue("fMinimizeToTray", false); - fMinimizeToTray = settings.value("fMinimizeToTray").toBool() && !fHideTrayIcon; + fMinimizeToTray = settings.value("fMinimizeToTray").toBool() && m_show_tray_icon; if (!settings.contains("fMinimizeOnClose")) settings.setValue("fMinimizeOnClose", false); @@ -122,6 +124,13 @@ void OptionsModel::Init(bool resetSettings) if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool())) addOverriddenOption("-upnp"); + if (!settings.contains("fUseNatpmp")) { + settings.setValue("fUseNatpmp", DEFAULT_NATPMP); + } + if (!gArgs.SoftSetBoolArg("-natpmp", settings.value("fUseNatpmp").toBool())) { + addOverriddenOption("-natpmp"); + } + if (!settings.contains("fListen")) settings.setValue("fListen", DEFAULT_LISTEN); if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool())) @@ -219,7 +228,7 @@ static ProxySetting GetProxySetting(QSettings &settings, const QString &name) return default_val; } // contains IP at index 0 and port at index 1 - QStringList ip_port = settings.value(name).toString().split(":", QString::SkipEmptyParts); + QStringList ip_port = GUIUtil::SplitSkipEmptyParts(settings.value(name).toString(), ":"); if (ip_port.size() == 2) { return {true, ip_port.at(0), ip_port.at(1)}; } else { // Invalid: return default @@ -272,8 +281,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const { case StartAtStartup: return GUIUtil::GetStartOnSystemStartup(); - case HideTrayIcon: - return fHideTrayIcon; + case ShowTrayIcon: + return m_show_tray_icon; case MinimizeToTray: return fMinimizeToTray; case MapPortUPnP: @@ -281,7 +290,13 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const return settings.value("fUseUPnP"); #else return false; -#endif +#endif // USE_UPNP + case MapPortNatpmp: +#ifdef USE_NATPMP + return settings.value("fUseNatpmp"); +#else + return false; +#endif // USE_NATPMP case MinimizeOnClose: return fMinimizeOnClose; @@ -342,10 +357,10 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in case StartAtStartup: successful = GUIUtil::SetStartOnSystemStartup(value.toBool()); break; - case HideTrayIcon: - fHideTrayIcon = value.toBool(); - settings.setValue("fHideTrayIcon", fHideTrayIcon); - Q_EMIT hideTrayIconChanged(fHideTrayIcon); + case ShowTrayIcon: + m_show_tray_icon = value.toBool(); + settings.setValue("fHideTrayIcon", !m_show_tray_icon); + Q_EMIT showTrayIconChanged(m_show_tray_icon); break; case MinimizeToTray: fMinimizeToTray = value.toBool(); @@ -353,7 +368,9 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in break; case MapPortUPnP: // core option - can be changed on-the-fly settings.setValue("fUseUPnP", value.toBool()); - node().mapPort(value.toBool()); + break; + case MapPortNatpmp: // core option - can be changed on-the-fly + settings.setValue("fUseNatpmp", value.toBool()); break; case MinimizeOnClose: fMinimizeOnClose = value.toBool(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 3d9e7bbb80..f7171951a1 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -45,9 +45,10 @@ public: enum OptionID { StartAtStartup, // bool - HideTrayIcon, // bool + ShowTrayIcon, // bool MinimizeToTray, // bool MapPortUPnP, // bool + MapPortNatpmp, // bool MinimizeOnClose, // bool ProxyUse, // bool ProxyIP, // QString @@ -78,7 +79,7 @@ public: void setDisplayUnit(const QVariant &value); /* Explicit getters */ - bool getHideTrayIcon() const { return fHideTrayIcon; } + bool getShowTrayIcon() const { return m_show_tray_icon; } bool getMinimizeToTray() const { return fMinimizeToTray; } bool getMinimizeOnClose() const { return fMinimizeOnClose; } int getDisplayUnit() const { return nDisplayUnit; } @@ -100,7 +101,7 @@ public: private: interfaces::Node* m_node = nullptr; /* Qt-only settings */ - bool fHideTrayIcon; + bool m_show_tray_icon; bool fMinimizeToTray; bool fMinimizeOnClose; QString language; @@ -118,7 +119,7 @@ private: Q_SIGNALS: void displayUnitChanged(int unit); void coinControlFeaturesChanged(bool); - void hideTrayIconChanged(bool); + void showTrayIconChanged(bool); }; #endif // BITCOIN_QT_OPTIONSMODEL_H diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index b536567c8b..bc542a0833 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,14 +12,19 @@ #include <qt/optionsmodel.h> #include <qt/platformstyle.h> #include <qt/transactionfilterproxy.h> +#include <qt/transactionoverviewwidget.h> #include <qt/transactiontablemodel.h> #include <qt/walletmodel.h> #include <QAbstractItemDelegate> #include <QApplication> +#include <QDateTime> #include <QPainter> #include <QStatusTipEvent> +#include <algorithm> +#include <map> + #define DECORATION_SIZE 54 #define NUM_ITEMS 5 @@ -33,7 +38,7 @@ public: QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC), platformStyle(_platformStyle) { - + connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged); } inline void paint(QPainter *painter, const QStyleOptionViewItem &option, @@ -66,13 +71,15 @@ public: painter->setPen(foreground); QRect boundingRect; - painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect); + painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter, address, &boundingRect); + int address_rect_min_width = boundingRect.width(); if (index.data(TransactionTableModel::WatchonlyRole).toBool()) { QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole)); QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight); iconWatchonly.paint(painter, watchonlyRect); + address_rect_min_width += 5 + watchonlyRect.width(); } if(amount < 0) @@ -93,23 +100,42 @@ public: { amountText = QString("[") + amountText + QString("]"); } - painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText); + + QRect amount_bounding_rect; + painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter, amountText, &amount_bounding_rect); painter->setPen(option.palette.color(QPalette::Text)); - painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date)); + QRect date_bounding_rect; + painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter, GUIUtil::dateTimeStr(date), &date_bounding_rect); + + const int minimum_width = std::max(address_rect_min_width, amount_bounding_rect.width() + date_bounding_rect.width()); + const auto search = m_minimum_width.find(index.row()); + if (search == m_minimum_width.end() || search->second != minimum_width) { + m_minimum_width[index.row()] = minimum_width; + Q_EMIT width_changed(index); + } painter->restore(); } inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override { - return QSize(DECORATION_SIZE, DECORATION_SIZE); + const auto search = m_minimum_width.find(index.row()); + const int minimum_text_width = search == m_minimum_width.end() ? 0 : search->second; + return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE}; } int unit; - const PlatformStyle *platformStyle; +Q_SIGNALS: + //! An intermediate signal for emitting from the `paint() const` member function. + void width_changed(const QModelIndex& index) const; + +private: + const PlatformStyle* platformStyle; + mutable std::map<int, int> m_minimum_width; }; + #include <qt/overviewpage.moc> OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) : @@ -125,7 +151,6 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) // use a SingleColorIcon for the "out of sync warning" icon QIcon icon = platformStyle->SingleColorIcon(":/icons/warning"); - icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503) ui->labelTransactionsStatus->setIcon(icon); ui->labelWalletStatus->setIcon(icon); @@ -135,7 +160,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false); - connect(ui->listTransactions, &QListView::clicked, this, &OverviewPage::handleTransactionClicked); + connect(ui->listTransactions, &TransactionOverviewWidget::clicked, this, &OverviewPage::handleTransactionClicked); // start with displaying the "out of sync" warnings showOutOfSyncWarning(true); diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 4cf673b6a6..578ef601fb 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 8679ced685..96f6202874 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -26,7 +26,6 @@ #include <QApplication> #include <QByteArray> #include <QDataStream> -#include <QDateTime> #include <QDebug> #include <QFile> #include <QFileOpenEvent> @@ -94,12 +93,12 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) SendCoinsRecipient r; if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty()) { - auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN); + auto tempChainParams = CreateChainParams(gArgs, CBaseChainParams::MAIN); if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { SelectParams(CBaseChainParams::MAIN); } else { - tempChainParams = CreateChainParams(CBaseChainParams::TESTNET); + tempChainParams = CreateChainParams(gArgs, CBaseChainParams::TESTNET); if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { SelectParams(CBaseChainParams::TESTNET); } diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index eaf2bafe59..08b83244ab 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 5220f8e138..bad81d894c 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -29,14 +29,16 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine return pLeft->nodeid < pRight->nodeid; case PeerTableModel::Address: return pLeft->addrName.compare(pRight->addrName) < 0; - case PeerTableModel::Subversion: - return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0; + case PeerTableModel::Network: + return pLeft->m_network < pRight->m_network; case PeerTableModel::Ping: return pLeft->m_min_ping_usec < pRight->m_min_ping_usec; case PeerTableModel::Sent: return pLeft->nSendBytes < pRight->nSendBytes; case PeerTableModel::Received: return pLeft->nRecvBytes < pRight->nRecvBytes; + case PeerTableModel::Subversion: + return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0; } return false; @@ -104,7 +106,6 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) : m_node(node), timer(nullptr) { - columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent"); priv.reset(new PeerTablePriv()); // set up timer for auto refresh @@ -133,13 +134,17 @@ void PeerTableModel::stopAutoRefresh() int PeerTableModel::rowCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return priv->size(); } int PeerTableModel::columnCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return columns.length(); } @@ -158,17 +163,21 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const case Address: // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName); - case Subversion: - return QString::fromStdString(rec->nodeStats.cleanSubVer); + case Network: + return GUIUtil::NetworkToQString(rec->nodeStats.m_network); case Ping: return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_usec); case Sent: return GUIUtil::formatBytes(rec->nodeStats.nSendBytes); case Received: return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes); + case Subversion: + return QString::fromStdString(rec->nodeStats.cleanSubVer); } } else if (role == Qt::TextAlignmentRole) { switch (index.column()) { + case Network: + return QVariant(Qt::AlignCenter); case Ping: case Sent: case Received: @@ -176,6 +185,11 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const default: return QVariant(); } + } else if (role == StatsRole) { + switch (index.column()) { + case NetNodeId: return QVariant::fromValue(rec); + default: return QVariant(); + } } return QVariant(); @@ -211,11 +225,6 @@ QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent return QModelIndex(); } -const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx) -{ - return priv->index(idx); -} - void PeerTableModel::refresh() { Q_EMIT layoutAboutToBeChanged(); diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 99de772ac0..7bff239507 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -28,6 +28,7 @@ struct CNodeCombinedStats { CNodeStateStats nodeStateStats; bool fNodeStateStatsAvailable; }; +Q_DECLARE_METATYPE(CNodeCombinedStats*) class NodeLessThan { @@ -52,7 +53,6 @@ class PeerTableModel : public QAbstractTableModel public: explicit PeerTableModel(interfaces::Node& node, QObject* parent); ~PeerTableModel(); - const CNodeCombinedStats *getNodeStats(int idx); int getRowByNodeId(NodeId nodeid); void startAutoRefresh(); void stopAutoRefresh(); @@ -60,10 +60,15 @@ public: enum ColumnIndex { NetNodeId = 0, Address = 1, - Ping = 2, - Sent = 3, - Received = 4, - Subversion = 5 + Network = 2, + Ping = 3, + Sent = 4, + Received = 5, + Subversion = 6 + }; + + enum { + StatsRole = Qt::UserRole, }; /** @name Methods overridden from QAbstractTableModel @@ -82,7 +87,7 @@ public Q_SLOTS: private: interfaces::Node& m_node; - QStringList columns; + const QStringList columns{tr("Peer Id"), tr("Address"), tr("Network"), tr("Ping"), tr("Sent"), tr("Received"), tr("User Agent")}; std::unique_ptr<PeerTablePriv> priv; QTimer *timer; }; diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 58167d4bb4..55ab6046cf 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -19,7 +19,7 @@ PSBTOperationsDialog::PSBTOperationsDialog( - QWidget* parent, WalletModel* wallet_model, ClientModel* client_model) : QDialog(parent), + QWidget* parent, WalletModel* wallet_model, ClientModel* client_model) : QDialog(parent, GUIUtil::dialog_flags), m_ui(new Ui::PSBTOperationsDialog), m_wallet_model(wallet_model), m_client_model(client_model) diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index c816e1f8ed..490826cbbb 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +9,7 @@ #include <QApplication> #include <QClipboard> #include <QDrag> +#include <QFontDatabase> #include <QMenu> #include <QMimeData> #include <QMouseEvent> @@ -64,26 +65,28 @@ bool QRImageWidget::setQR(const QString& data, const QString& text) } QRcode_free(code); - QImage qrAddrImage = QImage(QR_IMAGE_SIZE, QR_IMAGE_SIZE + (text.isEmpty() ? 0 : 20), QImage::Format_RGB32); + const int qr_image_size = QR_IMAGE_SIZE + (text.isEmpty() ? 0 : 2 * QR_IMAGE_MARGIN); + QImage qrAddrImage(qr_image_size, qr_image_size, QImage::Format_RGB32); qrAddrImage.fill(0xffffff); - QPainter painter(&qrAddrImage); - painter.drawImage(0, 0, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE)); + { + QPainter painter(&qrAddrImage); + painter.drawImage(QR_IMAGE_MARGIN, 0, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE)); - if (!text.isEmpty()) { - QFont font = GUIUtil::fixedPitchFont(); - font.setStyleStrategy(QFont::NoAntialias); - QRect paddedRect = qrAddrImage.rect(); + if (!text.isEmpty()) { + QRect paddedRect = qrAddrImage.rect(); + paddedRect.setHeight(QR_IMAGE_SIZE + QR_IMAGE_TEXT_MARGIN); - // calculate ideal font size - qreal font_size = GUIUtil::calculateIdealFontSize(paddedRect.width() - 20, text, font); - font.setPointSizeF(font_size); + QFont font = GUIUtil::fixedPitchFont(); + font.setStretch(QFont::SemiCondensed); + font.setLetterSpacing(QFont::AbsoluteSpacing, 1); + const qreal font_size = GUIUtil::calculateIdealFontSize(paddedRect.width() - 2 * QR_IMAGE_TEXT_MARGIN, text, font); + font.setPointSizeF(font_size); - painter.setFont(font); - paddedRect.setHeight(QR_IMAGE_SIZE+12); - painter.drawText(paddedRect, Qt::AlignBottom|Qt::AlignCenter, text); + painter.setFont(font); + painter.drawText(paddedRect, Qt::AlignBottom | Qt::AlignCenter, text); + } } - painter.end(); setPixmap(QPixmap::fromImage(qrAddrImage)); return true; @@ -95,15 +98,12 @@ bool QRImageWidget::setQR(const QString& data, const QString& text) QImage QRImageWidget::exportImage() { - if(!pixmap()) - return QImage(); - return pixmap()->toImage(); + return GUIUtil::GetImage(this); } void QRImageWidget::mousePressEvent(QMouseEvent *event) { - if(event->button() == Qt::LeftButton && pixmap()) - { + if (event->button() == Qt::LeftButton && GUIUtil::HasPixmap(this)) { event->accept(); QMimeData *mimeData = new QMimeData; mimeData->setImageData(exportImage()); @@ -118,7 +118,7 @@ void QRImageWidget::mousePressEvent(QMouseEvent *event) void QRImageWidget::saveImage() { - if(!pixmap()) + if (!GUIUtil::HasPixmap(this)) return; QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), nullptr); if (!fn.isEmpty()) @@ -129,14 +129,14 @@ void QRImageWidget::saveImage() void QRImageWidget::copyImage() { - if(!pixmap()) + if (!GUIUtil::HasPixmap(this)) return; QApplication::clipboard()->setImage(exportImage()); } void QRImageWidget::contextMenuEvent(QContextMenuEvent *event) { - if(!pixmap()) + if (!GUIUtil::HasPixmap(this)) return; contextMenu->exec(event->globalPos()); } diff --git a/src/qt/qrimagewidget.h b/src/qt/qrimagewidget.h index cca598c2ce..5dbba074a1 100644 --- a/src/qt/qrimagewidget.h +++ b/src/qt/qrimagewidget.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,7 +12,9 @@ static const int MAX_URI_LENGTH = 255; /* Size of exported QR Code image */ -static const int QR_IMAGE_SIZE = 300; +static constexpr int QR_IMAGE_SIZE = 300; +static constexpr int QR_IMAGE_TEXT_MARGIN = 10; +static constexpr int QR_IMAGE_MARGIN = 2 * QR_IMAGE_TEXT_MARGIN; QT_BEGIN_NAMESPACE class QMenu; diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index 2c72b2ecda..b32305f5e1 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index d374d610ee..0aea920c86 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,6 +8,7 @@ #include <qt/forms/ui_receivecoinsdialog.h> #include <qt/addresstablemodel.h> +#include <qt/guiutil.h> #include <qt/optionsmodel.h> #include <qt/platformstyle.h> #include <qt/receiverequestdialog.h> @@ -21,7 +22,7 @@ #include <QTextDocument> ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::ReceiveCoinsDialog), columnResizingFixer(nullptr), model(nullptr), diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index 27455e2906..9b89bd6a8b 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index d385c42821..78ae5c07da 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,7 +19,7 @@ #endif ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::ReceiveRequestDialog), model(nullptr) { diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h index 846478643d..c861680761 100644 --- a/src/qt/receiverequestdialog.h +++ b/src/qt/receiverequestdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 3e20368a36..18b913774b 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -36,15 +36,17 @@ RecentRequestsTableModel::~RecentRequestsTableModel() int RecentRequestsTableModel::rowCount(const QModelIndex &parent) const { - Q_UNUSED(parent); - + if (parent.isValid()) { + return 0; + } return list.length(); } int RecentRequestsTableModel::columnCount(const QModelIndex &parent) const { - Q_UNUSED(parent); - + if (parent.isValid()) { + return 0; + } return columns.length(); } diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index c0bd3461bb..b817b64e77 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/res/animation/makespinner.sh b/src/qt/res/animation/makespinner.sh index 4fa8dadf86..83142f5034 100755 --- a/src/qt/res/animation/makespinner.sh +++ b/src/qt/res/animation/makespinner.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2014-2019 The Bitcoin Core developers +# Copyright (c) 2014-2020 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/res/bitcoin-qt-res.rc b/src/qt/res/bitcoin-qt-res.rc index 94ae256477..e590b407b0 100644 --- a/src/qt/res/bitcoin-qt-res.rc +++ b/src/qt/res/bitcoin-qt-res.rc @@ -4,8 +4,8 @@ IDI_ICON2 ICON DISCARDABLE "icons/bitcoin_testnet.ico" #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_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_BUILD +#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD) #define VER_FILEVERSION VER_PRODUCTVERSION #define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 4c5601242e..a252685d2f 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -16,19 +16,24 @@ #include <chainparams.h> #include <interfaces/node.h> #include <netbase.h> -#include <rpc/server.h> #include <rpc/client.h> +#include <rpc/server.h> #include <util/strencodings.h> +#include <util/string.h> #include <util/system.h> #include <util/threadnames.h> #include <univalue.h> #ifdef ENABLE_WALLET +#ifdef USE_BDB +#include <wallet/bdb.h> +#endif #include <wallet/db.h> #include <wallet/wallet.h> #endif +#include <QDateTime> #include <QFont> #include <QKeyEvent> #include <QMenu> @@ -453,7 +458,21 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center()); } - QChar nonbreaking_hyphen(8209); + ui->splitter->restoreState(settings.value("PeersTabSplitterSizes").toByteArray()); + + constexpr QChar nonbreaking_hyphen(8209); + const std::vector<QString> CONNECTION_TYPE_DOC{ + tr("Inbound Full/Block Relay: initiated by peer"), + tr("Outbound Full Relay: default"), + tr("Outbound Block Relay: does not relay transactions or addresses"), + tr("Outbound Manual: added using RPC %1 or %2/%3 configuration options") + .arg("addnode") + .arg(QString(nonbreaking_hyphen) + "addnode") + .arg(QString(nonbreaking_hyphen) + "connect"), + tr("Outbound Feeler: short-lived, for testing addresses"), + tr("Outbound Address Fetch: short-lived, for soliciting addresses")}; + const QString list{"<ul><li>" + Join(CONNECTION_TYPE_DOC, QString("</li><li>")) + "</li></ul>"}; + ui->peerConnectionTypeLabel->setToolTip(ui->peerConnectionTypeLabel->toolTip().arg(list)); ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir")); ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir")); ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME)); @@ -479,13 +498,6 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty ui->WalletSelector->setVisible(false); ui->WalletSelectorLabel->setVisible(false); - // set library version labels -#ifdef ENABLE_WALLET - ui->berkeleyDBVersion->setText(QString::fromStdString(BerkeleyDatabaseVersion())); -#else - ui->label_berkeleyDBVersion->hide(); - ui->berkeleyDBVersion->hide(); -#endif // Register RPC timer interface rpcTimerInterface = new QtRPCTimerInterface(); // avoid accidentally overwriting an existing, non QTThread @@ -493,9 +505,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty m_node.rpcSetTimerInterfaceIfUnset(rpcTimerInterface); setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS); - - ui->detailWidget->hide(); - ui->peerHeading->setText(tr("Select a peer to view detailed information.")); + updateDetailWidget(); consoleFontSize = settings.value(fontSizeSettingsKey, QFont().pointSize()).toInt(); clear(); @@ -507,6 +517,7 @@ RPCConsole::~RPCConsole() { QSettings settings; settings.setValue("RPCConsoleWindowGeometry", saveGeometry()); + settings.setValue("PeersTabSplitterSizes", ui->splitter->saveState()); m_node.rpcUnsetTimerInterface(rpcTimerInterface); delete rpcTimerInterface; delete ui; @@ -626,7 +637,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ connect(disconnectAction, &QAction::triggered, this, &RPCConsole::disconnectSelectedNode); // peer table signal handling - update peer details when selecting new node - connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::peerSelected); + connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::updateDetailWidget); // peer table signal handling - update peer details when new nodes are added to the model connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::peerLayoutChanged); // peer table signal handling - cache selected node ids @@ -1021,25 +1032,11 @@ void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut) ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut)); } -void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected) -{ - Q_UNUSED(deselected); - - if (!clientModel || !clientModel->getPeerTableModel() || selected.indexes().isEmpty()) - return; - - const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row()); - if (stats) - updateNodeDetail(stats); -} - void RPCConsole::peerLayoutAboutToChange() { - QModelIndexList selected = ui->peerWidget->selectionModel()->selectedIndexes(); cachedNodeids.clear(); - for(int i = 0; i < selected.size(); i++) - { - const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.at(i).row()); + for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) { + const auto stats = peer.data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>(); cachedNodeids.append(stats->nodeStats.nodeid); } } @@ -1049,7 +1046,6 @@ void RPCConsole::peerLayoutChanged() if (!clientModel || !clientModel->getPeerTableModel()) return; - const CNodeCombinedStats *stats = nullptr; bool fUnselect = false; bool fReselect = false; @@ -1080,9 +1076,6 @@ void RPCConsole::peerLayoutChanged() fUnselect = true; fReselect = true; } - - // get fresh stats on the detail node. - stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); } if (fUnselect && selectedRow >= 0) { @@ -1097,15 +1090,21 @@ void RPCConsole::peerLayoutChanged() } } - if (stats) - updateNodeDetail(stats); + updateDetailWidget(); } -void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) +void RPCConsole::updateDetailWidget() { + const QList<QModelIndex> selected_peers = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId); + if (!clientModel || !clientModel->getPeerTableModel() || selected_peers.size() != 1) { + ui->detailWidget->hide(); + ui->peerHeading->setText(tr("Select a peer to view detailed information.")); + return; + } + const auto stats = selected_peers.first().data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>(); // update the detail ui with latest node information QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " "); - peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid)); + peerAddrDetails += tr("(peer id: %1)").arg(QString::number(stats->nodeStats.nodeid)); if (!stats->nodeStats.addrLocal.empty()) peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal)); ui->peerHeading->setText(peerAddrDetails); @@ -1121,8 +1120,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset)); ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion)); ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer)); - ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound")); - ui->peerHeight->setText(QString::number(stats->nodeStats.nStartingHeight)); + ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type, stats->nodeStats.fRelayTxes)); + ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network)); if (stats->nodeStats.m_permissionFlags == PF_NONE) { ui->peerPermissions->setText(tr("N/A")); } else { @@ -1148,6 +1147,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats) ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight)); else ui->peerCommonHeight->setText(tr("Unknown")); + + ui->peerHeight->setText(QString::number(stats->nodeStateStats.m_starting_height)); } ui->detailWidget->show(); @@ -1213,19 +1214,9 @@ void RPCConsole::banSelectedNode(int bantime) if (!clientModel) return; - // Get selected peer addresses - QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId); - for(int i = 0; i < nodes.count(); i++) - { - // 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; - + for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) { // Find possible nodes, ban it and clear the selected node - const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow); + const auto stats = peer.data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>(); if (stats) { m_node.ban(stats->nodeStats.addr, bantime); m_node.disconnectByAddress(stats->nodeStats.addr); @@ -1260,8 +1251,7 @@ void RPCConsole::clearSelectedNode() { ui->peerWidget->selectionModel()->clearSelection(); cachedNodeids.clear(); - ui->detailWidget->hide(); - ui->peerHeading->setText(tr("Select a peer to view detailed information.")); + updateDetailWidget(); } void RPCConsole::showOrHideBanTableIfRequired() diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 280c5bd71a..5f308dc36d 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -28,6 +28,7 @@ namespace Ui { } QT_BEGIN_NAMESPACE +class QDateTime; class QMenu; class QItemSelection; QT_END_NAMESPACE @@ -94,6 +95,8 @@ private Q_SLOTS: void showOrHideBanTableIfRequired(); /** clear the selected node */ void clearSelectedNode(); + /** show detailed information on ui about selected node */ + void updateDetailWidget(); public Q_SLOTS: void clear(bool clearHistory = true); @@ -115,8 +118,6 @@ public Q_SLOTS: void browseHistory(int offset); /** Scroll console view to end */ void scrollToEnd(); - /** Handle selection of peer in peers list */ - void peerSelected(const QItemSelection &selected, const QItemSelection &deselected); /** Handle selection caching before update */ void peerLayoutAboutToChange(); /** Handle updated peer information */ @@ -137,8 +138,6 @@ Q_SIGNALS: private: void startExecutor(); void setTrafficGraphRange(int mins); - /** show detailed information on ui about selected node */ - void updateNodeDetail(const CNodeCombinedStats *stats); enum ColumnWidths { diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 97fb88d71c..611f3584c3 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -28,12 +28,14 @@ #include <wallet/fees.h> #include <wallet/wallet.h> +#include <validation.h> + #include <QFontMetrics> #include <QScrollBar> #include <QSettings> #include <QTextDocument> -static const std::array<int, 9> confTargets = { {2, 4, 6, 12, 24, 48, 144, 504, 1008} }; +static constexpr std::array confTargets{2, 4, 6, 12, 24, 48, 144, 504, 1008}; int getConfTargetForIndex(int index) { if (index+1 > static_cast<int>(confTargets.size())) { return confTargets.back(); @@ -53,7 +55,7 @@ int getIndexForConfTarget(int target) { } SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::SendCoinsDialog), clientModel(nullptr), model(nullptr), @@ -134,7 +136,7 @@ void SendCoinsDialog::setClientModel(ClientModel *_clientModel) this->clientModel = _clientModel; if (_clientModel) { - connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateSmartFeeLabel); + connect(_clientModel, &ClientModel::numBlocksChanged, this, &SendCoinsDialog::updateNumberOfBlocks); } } @@ -171,8 +173,15 @@ void SendCoinsDialog::setModel(WalletModel *_model) } connect(ui->confTargetSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel); connect(ui->confTargetSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::updateFeeSectionControls); + connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::coinControlUpdateLabels); +#else connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls); connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels); +#endif + connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels); connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::updateSmartFeeLabel); connect(ui->optInRBF, &QCheckBox::stateChanged, this, &SendCoinsDialog::coinControlUpdateLabels); @@ -744,6 +753,12 @@ void SendCoinsDialog::updateCoinControlState(CCoinControl& ctrl) ctrl.fAllowWatchOnly = model->wallet().privateKeysDisabled(); } +void SendCoinsDialog::updateNumberOfBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state) { + if (sync_state == SynchronizationState::POST_INIT) { + updateSmartFeeLabel(); + } +} + void SendCoinsDialog::updateSmartFeeLabel() { if(!model || !model->getOptionsModel()) @@ -958,6 +973,9 @@ SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QStri setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); setDefaultButton(QMessageBox::Cancel); yesButton = button(QMessageBox::Yes); + if (confirmButtonText.isEmpty()) { + confirmButtonText = yesButton->text(); + } updateYesButton(); connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown); } diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 6961aa7821..4fc2f57cd6 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -17,6 +17,7 @@ class ClientModel; class PlatformStyle; class SendCoinsEntry; class SendCoinsRecipient; +enum class SynchronizationState; namespace Ui { class SendCoinsDialog; @@ -98,6 +99,7 @@ private Q_SLOTS: void coinControlClipboardLowOutput(); void coinControlClipboardChange(); void updateFeeSectionControls(); + void updateNumberOfBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool headers, SynchronizationState sync_state); void updateSmartFeeLabel(); Q_SIGNALS: @@ -113,7 +115,7 @@ class SendConfirmationDialog : public QMessageBox Q_OBJECT public: - SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "Send", QWidget* parent = nullptr); + SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "", QWidget* parent = nullptr); int exec() override; private Q_SLOTS: diff --git a/src/qt/sendcoinsrecipient.h b/src/qt/sendcoinsrecipient.h index 6619faf417..01135cdfef 100644 --- a/src/qt/sendcoinsrecipient.h +++ b/src/qt/sendcoinsrecipient.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 4835dd7954..2e7df60574 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -19,7 +19,7 @@ #include <QClipboard> SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::SignVerifyMessageDialog), model(nullptr), platformStyle(_platformStyle) @@ -120,7 +120,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); return; } - const PKHash* pkhash = boost::get<PKHash>(&destination); + const PKHash* pkhash = std::get_if<PKHash>(&destination); if (!pkhash) { ui->addressIn_SM->setValid(false); ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h index d33a2d038d..d98cb290a1 100644 --- a/src/qt/signverifymessagedialog.h +++ b/src/qt/signverifymessagedialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2015 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 8e381861a0..2292c01d6a 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -14,9 +14,12 @@ #include <interfaces/wallet.h> #include <qt/guiutil.h> #include <qt/networkstyle.h> +#include <qt/walletmodel.h> #include <util/system.h> #include <util/translation.h> +#include <functional> + #include <QApplication> #include <QCloseEvent> #include <QPainter> @@ -24,8 +27,8 @@ #include <QScreen> -SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) : - QWidget(nullptr, f), curAlignment(0) +SplashScreen::SplashScreen(const NetworkStyle* networkStyle) + : QWidget(), curAlignment(0) { // set reference point, paddings int paddingRight = 50; @@ -196,6 +199,7 @@ void SplashScreen::subscribeToCoreSignals() void SplashScreen::handleLoadWallet() { #ifdef ENABLE_WALLET + if (!WalletModel::isWalletEnabled()) return; m_handler_load_wallet = m_node->walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, false))); m_connected_wallets.emplace_back(std::move(wallet)); diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index a0cd677d3d..386039291c 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -28,7 +28,7 @@ class SplashScreen : public QWidget Q_OBJECT public: - explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle); + explicit SplashScreen(const NetworkStyle *networkStyle); ~SplashScreen(); void setNode(interfaces::Node& node); diff --git a/src/qt/test/addressbooktests.h b/src/qt/test/addressbooktests.h index 5de89c7592..ab52206466 100644 --- a/src/qt/test/addressbooktests.h +++ b/src/qt/test/addressbooktests.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,7 +15,7 @@ class Node; class AddressBookTests : public QObject { public: - AddressBookTests(interfaces::Node& node) : m_node(node) {} + explicit AddressBookTests(interfaces::Node& node) : m_node(node) {} interfaces::Node& m_node; Q_OBJECT diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index de1fbcb94c..0d9928d363 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,17 +14,26 @@ #include <QDir> #include <QtGlobal> -static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request) +static RPCHelpMan rpcNestedTest_rpc() { - if (request.fHelp) { - return "help message"; - } - return request.params.write(0, 0); + return RPCHelpMan{ + "rpcNestedTest", + "echo the passed string(s)", + { + {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, + {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, + {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""}, + }, + {}, + RPCExamples{""}, + [](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + return request.params.write(0, 0); + }, + }; } -static const CRPCCommand vRPCCommands[] = -{ - { "test", "rpcNestedTest", &rpcNestedTest_rpc, {} }, +static const CRPCCommand vRPCCommands[] = { + {"test", &rpcNestedTest_rpc}, }; void RPCNestedTests::rpcNestedTests() @@ -34,41 +43,41 @@ void RPCNestedTests::rpcNestedTests() tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]); TestingSetup test; + m_node.setContext(&test.m_node); if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished(); std::string result; std::string result2; std::string filtered; - interfaces::Node* node = &m_node; - RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path QVERIFY(result=="main"); QVERIFY(filtered == "getblockchaininfo()[chain]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())"); //simple 2 level nesting - RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getblock(getbestblockhash())[hash], true)"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblock(getbestblockhash())"); //simple 2 level nesting + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblock(getblock(getbestblockhash())[hash], true)"); - RPCConsole::RPCExecuteCommandLine(*node, result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter - RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo"); QVERIFY(result.substr(0,1) == "{"); - RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()"); QVERIFY(result.substr(0,1) == "{"); - RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo "); //whitespace at the end will be tolerated + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo "); //whitespace at the end will be tolerated QVERIFY(result.substr(0,1) == "{"); - (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key + (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key QVERIFY(result == "null"); - (RPCConsole::RPCExecuteCommandLine(*node, result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed - (RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed + (RPCConsole::RPCExecuteCommandLine(m_node, result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed + (RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed QVERIFY(result == result2); - (RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed + (RPCConsole::RPCExecuteCommandLine(m_node, result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parameters is allowed QVERIFY(result == result2); - RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())[tx][0]", &filtered); + RPCConsole::RPCExecuteCommandLine(m_node, result, "getblock(getbestblockhash())[tx][0]", &filtered); QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"); QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]"); @@ -93,35 +102,35 @@ void RPCNestedTests::rpcNestedTests() RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered); QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest"); QVERIFY(result == "[]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest ''"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest ''"); QVERIFY(result == "[\"\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest \"\""); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest \"\""); QVERIFY(result == "[\"\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest '' abc"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest '' abc"); QVERIFY(result == "[\"\",\"abc\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc '' abc"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc '' abc"); QVERIFY(result == "[\"abc\",\"\",\"abc\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc abc"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc abc"); QVERIFY(result == "[\"abc\",\"abc\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc\t\tabc"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc\t\tabc"); QVERIFY(result == "[\"abc\",\"abc\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc )"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc )"); QVERIFY(result == "[\"abc\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc )"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest( abc )"); QVERIFY(result == "[\"abc\"]"); - RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc , cba )"); + RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest( abc , cba )"); QVERIFY(result == "[\"abc\",\"cba\"]"); // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3) - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax - (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments - (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()()()")); //tolerate non command brackts - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(True)"), UniValue); //invalid argument - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "a(getblockchaininfo(True))"), UniValue); //method not found - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using , - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using , - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax + (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments + (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()")); //tolerate non command brackets + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(True)"), UniValue); //invalid argument + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "a(getblockchaininfo(True))"), UniValue); //method not found + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tolerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tolerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tolerate empty arguments when using , } diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h index 0a00d1113a..28dc7140e1 100644 --- a/src/qt/test/rpcnestedtests.h +++ b/src/qt/test/rpcnestedtests.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,7 +15,7 @@ class Node; class RPCNestedTests : public QObject { public: - RPCNestedTests(interfaces::Node& node) : m_node(node) {} + explicit RPCNestedTests(interfaces::Node& node) : m_node(node) {} interfaces::Node& m_node; Q_OBJECT diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 86356b43c8..9ef5fe8fc7 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp index 759832381b..987d921f03 100644 --- a/src/qt/test/util.cpp +++ b/src/qt/test/util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/util.h b/src/qt/test/util.h index 950314da3b..df5931a032 100644 --- a/src/qt/test/util.h +++ b/src/qt/test/util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/test/wallettests.h b/src/qt/test/wallettests.h index 8ee40bf07f..6044bedb1d 100644 --- a/src/qt/test/wallettests.h +++ b/src/qt/test/wallettests.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,7 +15,7 @@ class Node; class WalletTests : public QObject { public: - WalletTests(interfaces::Node& node) : m_node(node) {} + explicit WalletTests(interfaces::Node& node) : m_node(node) {} interfaces::Node& m_node; Q_OBJECT diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 6428fc4daf..dabdf9d887 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp index 715e312b19..6f31d8463f 100644 --- a/src/qt/transactiondescdialog.cpp +++ b/src/qt/transactiondescdialog.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. @@ -11,7 +11,7 @@ #include <QModelIndex> TransactionDescDialog::TransactionDescDialog(const QModelIndex &idx, QWidget *parent) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::TransactionDescDialog) { ui->setupUi(this); diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index d6bb84f7e6..693b363692 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionoverviewwidget.h b/src/qt/transactionoverviewwidget.h new file mode 100644 index 0000000000..2bdead7bc4 --- /dev/null +++ b/src/qt/transactionoverviewwidget.h @@ -0,0 +1,41 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H +#define BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H + +#include <qt/transactiontablemodel.h> + +#include <QListView> +#include <QSize> +#include <QSizePolicy> + +QT_BEGIN_NAMESPACE +class QShowEvent; +class QWidget; +QT_END_NAMESPACE + +class TransactionOverviewWidget : public QListView +{ + Q_OBJECT + +public: + explicit TransactionOverviewWidget(QWidget* parent = nullptr) : QListView(parent) {} + + QSize sizeHint() const override + { + return {sizeHintForColumn(TransactionTableModel::ToAddress), QListView::sizeHint().height()}; + } + +protected: + void showEvent(QShowEvent* event) override + { + Q_UNUSED(event); + QSizePolicy sp = sizePolicy(); + sp.setHorizontalPolicy(QSizePolicy::Minimum); + setSizePolicy(sp); + } +}; + +#endif // BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 632a18de5c..77fec93f0f 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -123,7 +123,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface continue; } - if (!boost::get<CNoDestination>(&wtx.txout_address[nOut])) + if (!std::get_if<CNoDestination>(&wtx.txout_address[nOut])) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index c983c527c0..e10243a28a 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index c560dc58e7..e6d483364c 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,6 +19,7 @@ #include <uint256.h> #include <algorithm> +#include <functional> #include <QColor> #include <QDateTime> @@ -54,6 +55,30 @@ struct TxLessThan } }; +// queue notifications to show a non freezing progress dialog e.g. for rescan +struct TransactionNotification +{ +public: + TransactionNotification() {} + TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction): + hash(_hash), status(_status), showTransaction(_showTransaction) {} + + void invoke(QObject *ttm) + { + QString strHash = QString::fromStdString(hash.GetHex()); + qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status); + bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection, + Q_ARG(QString, strHash), + Q_ARG(int, status), + Q_ARG(bool, showTransaction)); + assert(invoked); + } +private: + uint256 hash; + ChangeType status; + bool showTransaction; +}; + // Private implementation class TransactionTablePriv { @@ -71,6 +96,12 @@ public: */ QList<TransactionRecord> cachedWallet; + bool fQueueNotifications = false; + std::vector< TransactionNotification > vQueueNotifications; + + void NotifyTransactionChanged(const uint256 &hash, ChangeType status); + void ShowProgress(const std::string &title, int nProgress); + /* Query entire wallet anew from core. */ void refreshWallet(interfaces::Wallet& wallet) @@ -259,13 +290,17 @@ void TransactionTableModel::updateConfirmations() int TransactionTableModel::rowCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return priv->size(); } int TransactionTableModel::columnCount(const QModelIndex &parent) const { - Q_UNUSED(parent); + if (parent.isValid()) { + return 0; + } return columns.length(); } @@ -674,34 +709,7 @@ void TransactionTableModel::updateDisplayUnit() Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount)); } -// queue notifications to show a non freezing progress dialog e.g. for rescan -struct TransactionNotification -{ -public: - TransactionNotification() {} - TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction): - hash(_hash), status(_status), showTransaction(_showTransaction) {} - - void invoke(QObject *ttm) - { - QString strHash = QString::fromStdString(hash.GetHex()); - qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status); - bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection, - Q_ARG(QString, strHash), - Q_ARG(int, status), - Q_ARG(bool, showTransaction)); - assert(invoked); - } -private: - uint256 hash; - ChangeType status; - bool showTransaction; -}; - -static bool fQueueNotifications = false; -static std::vector< TransactionNotification > vQueueNotifications; - -static void NotifyTransactionChanged(TransactionTableModel *ttm, const uint256 &hash, ChangeType status) +void TransactionTablePriv::NotifyTransactionChanged(const uint256 &hash, ChangeType status) { // Find transaction in wallet // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread) @@ -714,10 +722,10 @@ static void NotifyTransactionChanged(TransactionTableModel *ttm, const uint256 & vQueueNotifications.push_back(notification); return; } - notification.invoke(ttm); + notification.invoke(parent); } -static void ShowProgress(TransactionTableModel *ttm, const std::string &title, int nProgress) +void TransactionTablePriv::ShowProgress(const std::string &title, int nProgress) { if (nProgress == 0) fQueueNotifications = true; @@ -726,27 +734,27 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i { fQueueNotifications = false; if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons - bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true)); + bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true)); assert(invoked); } for (unsigned int i = 0; i < vQueueNotifications.size(); ++i) { if (vQueueNotifications.size() - i <= 10) { - bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false)); + bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false)); assert(invoked); } - vQueueNotifications[i].invoke(ttm); + vQueueNotifications[i].invoke(parent); } - std::vector<TransactionNotification >().swap(vQueueNotifications); // clear + vQueueNotifications.clear(); } } void TransactionTableModel::subscribeToCoreSignals() { // Connect signals to wallet - m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(std::bind(NotifyTransactionChanged, this, std::placeholders::_1, std::placeholders::_2)); - m_handler_show_progress = walletModel->wallet().handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2)); + m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(std::bind(&TransactionTablePriv::NotifyTransactionChanged, priv, std::placeholders::_1, std::placeholders::_2)); + m_handler_show_progress = walletModel->wallet().handleShowProgress(std::bind(&TransactionTablePriv::ShowProgress, priv, std::placeholders::_1, std::placeholders::_2)); } void TransactionTableModel::unsubscribeFromCoreSignals() diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 4b699d4d7d..f8576edd59 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 54ecfc38ec..0cf6480b82 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -237,7 +237,7 @@ void TransactionView::setModel(WalletModel *_model) if (_model->getOptionsModel()) { // Add third party transaction URLs to context menu - QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts); + QStringList listUrls = GUIUtil::SplitSkipEmptyParts(_model->getOptionsModel()->getThirdPartyTxUrls(), "|"); for (int i = 0; i < listUrls.size(); ++i) { QString url = listUrls[i].trimmed(); @@ -275,30 +275,30 @@ void TransactionView::chooseDate(int idx) break; case Today: transactionProxyModel->setDateRange( - QDateTime(current), + GUIUtil::StartOfDay(current), TransactionFilterProxy::MAX_DATE); break; case ThisWeek: { // Find last Monday QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1)); transactionProxyModel->setDateRange( - QDateTime(startOfWeek), + GUIUtil::StartOfDay(startOfWeek), TransactionFilterProxy::MAX_DATE); } break; case ThisMonth: transactionProxyModel->setDateRange( - QDateTime(QDate(current.year(), current.month(), 1)), + GUIUtil::StartOfDay(QDate(current.year(), current.month(), 1)), TransactionFilterProxy::MAX_DATE); break; case LastMonth: transactionProxyModel->setDateRange( - QDateTime(QDate(current.year(), current.month(), 1).addMonths(-1)), - QDateTime(QDate(current.year(), current.month(), 1))); + GUIUtil::StartOfDay(QDate(current.year(), current.month(), 1).addMonths(-1)), + GUIUtil::StartOfDay(QDate(current.year(), current.month(), 1))); break; case ThisYear: transactionProxyModel->setDateRange( - QDateTime(QDate(current.year(), 1, 1)), + GUIUtil::StartOfDay(QDate(current.year(), 1, 1)), TransactionFilterProxy::MAX_DATE); break; case Range: @@ -583,8 +583,8 @@ void TransactionView::dateRangeChanged() if(!transactionProxyModel) return; transactionProxyModel->setDateRange( - QDateTime(dateFrom->date()), - QDateTime(dateTo->date()).addDays(1)); + GUIUtil::StartOfDay(dateFrom->date()), + GUIUtil::StartOfDay(dateTo->date()).addDays(1)); } void TransactionView::focusTransaction(const QModelIndex &idx) diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 9ce7f4ad97..b268823066 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index b7f85446f4..05499b2a41 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -29,7 +29,7 @@ /** "Help message" or "About" dialog box */ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : - QDialog(parent), + QDialog(parent, GUIUtil::dialog_flags), ui(new Ui::HelpMessageDialog) { ui->setupUi(this); diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index d9e0274d01..7a89325ddf 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -128,10 +128,20 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal } // Instantiate model and register it. - WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, nullptr); - // Handler callback runs in a different thread so fix wallet model thread affinity. + WalletModel* wallet_model = new WalletModel(std::move(wallet), m_client_model, m_platform_style, + nullptr /* required for the following moveToThread() call */); + + // Move WalletModel object to the thread that created the WalletController + // object (GUI main thread), instead of the current thread, which could be + // an outside wallet thread or RPC thread sending a LoadWallet notification. + // This ensures queued signals sent to the WalletModel object will be + // handled on the GUI event loop. wallet_model->moveToThread(thread()); - wallet_model->setParent(this); + // setParent(parent) must be called in the thread which created the parent object. More details in #18948. + GUIUtil::ObjectInvoke(this, [wallet_model, this] { + wallet_model->setParent(this); + }, GUIUtil::blockingGUIThreadConnection()); + m_wallets.push_back(wallet_model); // WalletModel::startPollBalance needs to be called in a thread managed by @@ -142,7 +152,7 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal connect(wallet_model, &WalletModel::unload, this, [this, wallet_model] { // Defer removeAndDeleteWallet when no modal widget is active. - // TODO: remove this workaround by removing usage of QDiallog::exec. + // TODO: remove this workaround by removing usage of QDialog::exec. if (QApplication::activeModalWidget()) { connect(qApp, &QApplication::focusWindowChanged, wallet_model, [this, wallet_model]() { if (!QApplication::activeModalWidget()) { @@ -157,7 +167,6 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal // Re-emit coinsSent signal from wallet model. connect(wallet_model, &WalletModel::coinsSent, this, &WalletController::coinsSent); - // Notify walletAdded signal on the GUI thread. Q_EMIT walletAdded(wallet_model); return wallet_model; diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index f16761d6b2..02b3c62867 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -2,12 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <qt/createwalletdialog.h> -#include <qt/walletcontroller.h> #include <qt/walletframe.h> -#include <qt/walletmodel.h> #include <qt/bitcoingui.h> +#include <qt/createwalletdialog.h> +#include <qt/overviewpage.h> +#include <qt/walletcontroller.h> +#include <qt/walletmodel.h> #include <qt/walletview.h> #include <cassert> @@ -18,10 +19,11 @@ #include <QPushButton> #include <QVBoxLayout> -WalletFrame::WalletFrame(const PlatformStyle *_platformStyle, BitcoinGUI *_gui) : - QFrame(_gui), - gui(_gui), - platformStyle(_platformStyle) +WalletFrame::WalletFrame(const PlatformStyle* _platformStyle, BitcoinGUI* _gui) + : QFrame(_gui), + gui(_gui), + platformStyle(_platformStyle), + m_size_hint(OverviewPage{platformStyle, nullptr}.sizeHint()) { // Leave HBox hook for adding a list view later QHBoxLayout *walletFrameLayout = new QHBoxLayout(this); @@ -104,9 +106,24 @@ void WalletFrame::setCurrentWallet(WalletModel* wallet_model) { if (mapWalletViews.count(wallet_model) == 0) return; + // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget. + WalletView* view_about_to_hide = currentWalletView(); + if (view_about_to_hide) { + QSizePolicy sp = view_about_to_hide->sizePolicy(); + sp.setHorizontalPolicy(QSizePolicy::Ignored); + view_about_to_hide->setSizePolicy(sp); + } + WalletView *walletView = mapWalletViews.value(wallet_model); - walletStack->setCurrentWidget(walletView); assert(walletView); + + // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously. + QSizePolicy sp = walletView->sizePolicy(); + sp.setHorizontalPolicy(QSizePolicy::Preferred); + walletView->setSizePolicy(sp); + walletView->updateGeometry(); + + walletStack->setCurrentWidget(walletView); walletView->updateEncryptionStatus(); } @@ -194,11 +211,11 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard) } } -void WalletFrame::encryptWallet(bool status) +void WalletFrame::encryptWallet() { WalletView *walletView = currentWalletView(); if (walletView) - walletView->encryptWallet(status); + walletView->encryptWallet(); } void WalletFrame::backupWallet() diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 2b5f263468..f57f8678d6 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -45,6 +45,8 @@ public: void showOutOfSyncWarning(bool fShow); + QSize sizeHint() const override { return m_size_hint; } + Q_SIGNALS: /** Notify that the user has requested more information about the out-of-sync warning */ void requestedSyncWarningInfo(); @@ -59,6 +61,8 @@ private: const PlatformStyle *platformStyle; + const QSize m_size_hint; + public: WalletView* currentWalletView() const; WalletModel* currentWalletModel() const; @@ -82,7 +86,7 @@ public Q_SLOTS: void gotoLoadPSBT(bool from_clipboard = false); /** Encrypt the wallet */ - void encryptWallet(bool status); + void encryptWallet(); /** Backup the wallet */ void backupWallet(); /** Change encrypted wallet passphrase */ diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 6a3f903206..58427b42cc 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -29,6 +29,7 @@ #include <wallet/wallet.h> // for CRecipient #include <stdint.h> +#include <functional> #include <QDebug> #include <QMessageBox> @@ -313,12 +314,9 @@ WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const } } -bool WalletModel::setWalletEncrypted(bool encrypted, const SecureString &passphrase) +bool WalletModel::setWalletEncrypted(const SecureString& passphrase) { - if (encrypted) { - return m_wallet->encryptWallet(passphrase); - } - return false; + return m_wallet->encryptWallet(passphrase); } bool WalletModel::setWalletLocked(bool locked, const SecureString &passPhrase) @@ -517,6 +515,13 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) questionString.append("</td><td>"); questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee)); questionString.append("</td></tr></table>"); + + // Display warning in the "Confirm fee bump" window if the "Coin Control Features" option is enabled + if (getOptionsModel()->getCoinControlFeatures()) { + questionString.append("<br><br>"); + questionString.append(tr("Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.")); + } + SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString); confirmationDialog.exec(); QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result()); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index fd52db2da3..9a3c3f2f66 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -105,7 +105,7 @@ public: SendCoinsReturn sendCoins(WalletModelTransaction &transaction); // Wallet encryption - bool setWalletEncrypted(bool encrypted, const SecureString &passphrase); + bool setWalletEncrypted(const SecureString& passphrase); // Passphrase only needed when unlocking bool setWalletLocked(bool locked, const SecureString &passPhrase=SecureString()); bool changePassphrase(const SecureString &oldPass, const SecureString &newPass); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 2fc883a5f5..b1e6b43e60 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -258,11 +258,11 @@ void WalletView::updateEncryptionStatus() Q_EMIT encryptionStatusChanged(); } -void WalletView::encryptWallet(bool status) +void WalletView::encryptWallet() { if(!walletModel) return; - AskPassphraseDialog dlg(status ? AskPassphraseDialog::Encrypt : AskPassphraseDialog::Decrypt, this); + AskPassphraseDialog dlg(AskPassphraseDialog::Encrypt, this); dlg.setModel(walletModel); dlg.exec(); diff --git a/src/qt/walletview.h b/src/qt/walletview.h index f186554758..68f8a5e95b 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -92,7 +92,7 @@ public Q_SLOTS: */ void processNewTransaction(const QModelIndex& parent, int start, int /*end*/); /** Encrypt the wallet */ - void encryptWallet(bool status); + void encryptWallet(); /** Backup the wallet */ void backupWallet(); /** Change encrypted wallet passphrase */ diff --git a/src/randomenv.cpp b/src/randomenv.cpp index 073d82b491..9248db1539 100644 --- a/src/randomenv.cpp +++ b/src/randomenv.cpp @@ -53,7 +53,7 @@ #include <sys/vmmeter.h> #endif #endif -#ifdef __linux__ +#if defined(HAVE_STRONG_GETAUXVAL) || defined(HAVE_WEAK_GETAUXVAL) #include <sys/auxv.h> #endif @@ -67,8 +67,9 @@ void RandAddSeedPerfmon(CSHA512& hasher) #ifdef WIN32 // Seed with the entire set of perfmon data - // This can take up to 2 seconds, so only do it every 10 minutes - static std::atomic<std::chrono::seconds> last_perfmon{std::chrono::seconds{0}}; + // This can take up to 2 seconds, so only do it every 10 minutes. + // Initialize last_perfmon to 0 seconds, we don't skip the first call. + static std::atomic<std::chrono::seconds> last_perfmon{0s}; auto last_time = last_perfmon.load(); auto current_time = GetTime<std::chrono::seconds>(); if (current_time < last_time + std::chrono::minutes{10}) return; @@ -83,7 +84,7 @@ void RandAddSeedPerfmon(CSHA512& hasher) ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", nullptr, nullptr, vData.data(), &nSize); if (ret != ERROR_MORE_DATA || vData.size() >= nMaxSize) break; - vData.resize(std::max((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially + vData.resize(std::min((vData.size() * 3) / 2, nMaxSize)); // Grow size of buffer exponentially } RegCloseKey(HKEY_PERFORMANCE_DATA); if (ret == ERROR_SUCCESS) { @@ -325,7 +326,7 @@ void RandAddStaticEnv(CSHA512& hasher) // Bitcoin client version hasher << CLIENT_VERSION; -#ifdef __linux__ +#if defined(HAVE_STRONG_GETAUXVAL) || defined(HAVE_WEAK_GETAUXVAL) // Information available through getauxval() # ifdef AT_HWCAP hasher << getauxval(AT_HWCAP); @@ -345,7 +346,7 @@ void RandAddStaticEnv(CSHA512& hasher) const char* exec_str = (const char*)getauxval(AT_EXECFN); if (exec_str) hasher.Write((const unsigned char*)exec_str, strlen(exec_str) + 1); # endif -#endif // __linux__ +#endif // HAVE_STRONG_GETAUXVAL || HAVE_WEAK_GETAUXVAL #ifdef HAVE_GETCPUID AddAllCPUID(hasher); diff --git a/src/rest.cpp b/src/rest.cpp index 949cc9d84a..678ffdb760 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 0bb7342db0..e41a78f917 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -17,6 +17,7 @@ #include <node/coinstats.h> #include <node/context.h> #include <node/utxo_snapshot.h> +#include <policy/fees.h> #include <policy/feerate.h> #include <policy/policy.h> #include <policy/rbf.h> @@ -65,7 +66,7 @@ NodeContext& EnsureNodeContext(const util::Ref& context) CTxMemPool& EnsureMemPool(const util::Ref& context) { - NodeContext& node = EnsureNodeContext(context); + const NodeContext& node = EnsureNodeContext(context); if (!node.mempool) { throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found"); } @@ -74,13 +75,22 @@ CTxMemPool& EnsureMemPool(const util::Ref& context) ChainstateManager& EnsureChainman(const util::Ref& context) { - NodeContext& node = EnsureNodeContext(context); + const NodeContext& node = EnsureNodeContext(context); if (!node.chainman) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found"); } return *node.chainman; } +CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context) +{ + NodeContext& node = EnsureNodeContext(context); + if (!node.fee_estimator) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled"); + } + return *node.fee_estimator; +} + /* Calculate the difficulty for a given block index. */ double GetDifficulty(const CBlockIndex* blockindex) @@ -162,16 +172,21 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("versionHex", strprintf("%08x", block.nVersion)); result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); UniValue txs(UniValue::VARR); - for(const auto& tx : block.vtx) - { - if(txDetails) - { + if (txDetails) { + CBlockUndo blockUndo; + const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex); + for (size_t i = 0; i < block.vtx.size(); ++i) { + const CTransactionRef& tx = block.vtx.at(i); + // coinbase transaction (i == 0) doesn't have undo data + const CTxUndo* txundo = (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr; UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); + TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo); txs.push_back(objTx); } - else + } else { + for (const CTransactionRef& tx : block.vtx) { txs.push_back(tx->GetHash().GetHex()); + } } result.pushKV("tx", txs); result.pushKV("time", block.GetBlockTime()); @@ -926,9 +941,9 @@ static RPCHelpMan getblock() {RPCResult::Type::OBJ, "", "", { {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"}, + {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"}, }}, }}, - {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"}, }}, }, RPCExamples{ @@ -1268,7 +1283,7 @@ RPCHelpMan getblockchaininfo() RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::STR, "chain", "current network name (main, test, regtest)"}, + {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"}, {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"}, {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"}, {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"}, @@ -1355,6 +1370,7 @@ RPCHelpMan getblockchaininfo() BuriedForkDescPushBack(softforks, "csv", consensusParams.CSVHeight); BuriedForkDescPushBack(softforks, "segwit", consensusParams.SegwitHeight); BIP9SoftForkDescPushBack(softforks, "testdummy", consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); + BIP9SoftForkDescPushBack(softforks, "taproot", consensusParams, Consensus::DEPLOYMENT_TAPROOT); obj.pushKV("softforks", softforks); obj.pushKV("warnings", GetWarnings(false).original); @@ -1816,12 +1832,12 @@ static RPCHelpMan getblockstats() {RPCResult::Type::NUM, "outs", "The number of outputs"}, {RPCResult::Type::NUM, "subsidy", "The block subsidy"}, {RPCResult::Type::NUM, "swtotal_size", "Total size of all segwit transactions"}, - {RPCResult::Type::NUM, "swtotal_weight", "Total weight of all segwit transactions divided by segwit scale factor (4)"}, + {RPCResult::Type::NUM, "swtotal_weight", "Total weight of all segwit transactions"}, {RPCResult::Type::NUM, "swtxs", "The number of segwit transactions"}, {RPCResult::Type::NUM, "time", "The block time"}, {RPCResult::Type::NUM, "total_out", "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"}, {RPCResult::Type::NUM, "total_size", "Total size of all non-coinbase transactions"}, - {RPCResult::Type::NUM, "total_weight", "Total weight of all non-coinbase transactions divided by segwit scale factor (4)"}, + {RPCResult::Type::NUM, "total_weight", "Total weight of all non-coinbase transactions"}, {RPCResult::Type::NUM, "totalfee", "The fee total"}, {RPCResult::Type::NUM, "txs", "The number of transactions (including coinbase)"}, {RPCResult::Type::NUM, "utxo_increase", "The increase/decrease in the number of unspent outputs"}, @@ -2383,10 +2399,10 @@ static RPCHelpMan dumptxoutset() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - fs::path path = fs::absolute(request.params[0].get_str(), GetDataDir()); + const fs::path path = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str()); // Write to a temporary path and then move into `path` on completion // to avoid confusion due to an interruption. - fs::path temppath = fs::absolute(request.params[0].get_str() + ".incomplete", GetDataDir()); + const fs::path temppath = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str() + ".incomplete"); if (fs::exists(path)) { throw JSONRPCError( @@ -2464,41 +2480,41 @@ void RegisterBlockchainRPCCommands(CRPCTable &t) { // clang-format off static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "blockchain", "getblockchaininfo", &getblockchaininfo, {} }, - { "blockchain", "getchaintxstats", &getchaintxstats, {"nblocks", "blockhash"} }, - { "blockchain", "getblockstats", &getblockstats, {"hash_or_height", "stats"} }, - { "blockchain", "getbestblockhash", &getbestblockhash, {} }, - { "blockchain", "getblockcount", &getblockcount, {} }, - { "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} }, - { "blockchain", "getblockhash", &getblockhash, {"height"} }, - { "blockchain", "getblockheader", &getblockheader, {"blockhash","verbose"} }, - { "blockchain", "getchaintips", &getchaintips, {} }, - { "blockchain", "getdifficulty", &getdifficulty, {} }, - { "blockchain", "getmempoolancestors", &getmempoolancestors, {"txid","verbose"} }, - { "blockchain", "getmempooldescendants", &getmempooldescendants, {"txid","verbose"} }, - { "blockchain", "getmempoolentry", &getmempoolentry, {"txid"} }, - { "blockchain", "getmempoolinfo", &getmempoolinfo, {} }, - { "blockchain", "getrawmempool", &getrawmempool, {"verbose", "mempool_sequence"} }, - { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} }, - { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {"hash_type"} }, - { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} }, - { "blockchain", "savemempool", &savemempool, {} }, - { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} }, - - { "blockchain", "preciousblock", &preciousblock, {"blockhash"} }, - { "blockchain", "scantxoutset", &scantxoutset, {"action", "scanobjects"} }, - { "blockchain", "getblockfilter", &getblockfilter, {"blockhash", "filtertype"} }, +{ // category actor (function) + // --------------------- ------------------------ + { "blockchain", &getblockchaininfo, }, + { "blockchain", &getchaintxstats, }, + { "blockchain", &getblockstats, }, + { "blockchain", &getbestblockhash, }, + { "blockchain", &getblockcount, }, + { "blockchain", &getblock, }, + { "blockchain", &getblockhash, }, + { "blockchain", &getblockheader, }, + { "blockchain", &getchaintips, }, + { "blockchain", &getdifficulty, }, + { "blockchain", &getmempoolancestors, }, + { "blockchain", &getmempooldescendants, }, + { "blockchain", &getmempoolentry, }, + { "blockchain", &getmempoolinfo, }, + { "blockchain", &getrawmempool, }, + { "blockchain", &gettxout, }, + { "blockchain", &gettxoutsetinfo, }, + { "blockchain", &pruneblockchain, }, + { "blockchain", &savemempool, }, + { "blockchain", &verifychain, }, + + { "blockchain", &preciousblock, }, + { "blockchain", &scantxoutset, }, + { "blockchain", &getblockfilter, }, /* Not shown in help */ - { "hidden", "invalidateblock", &invalidateblock, {"blockhash"} }, - { "hidden", "reconsiderblock", &reconsiderblock, {"blockhash"} }, - { "hidden", "waitfornewblock", &waitfornewblock, {"timeout"} }, - { "hidden", "waitforblock", &waitforblock, {"blockhash","timeout"} }, - { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} }, - { "hidden", "syncwithvalidationinterfacequeue", &syncwithvalidationinterfacequeue, {} }, - { "hidden", "dumptxoutset", &dumptxoutset, {"path"} }, + { "hidden", &invalidateblock, }, + { "hidden", &reconsiderblock, }, + { "hidden", &waitfornewblock, }, + { "hidden", &waitforblock, }, + { "hidden", &waitforblockheight, }, + { "hidden", &syncwithvalidationinterfacequeue, }, + { "hidden", &dumptxoutset, }, }; // clang-format on for (const auto& c : commands) { diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 5b362bf211..e4ce80400e 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -15,6 +15,7 @@ extern RecursiveMutex cs_main; class CBlock; class CBlockIndex; +class CBlockPolicyEstimator; class CTxMemPool; class ChainstateManager; class UniValue; @@ -54,5 +55,6 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], NodeContext& EnsureNodeContext(const util::Ref& context); CTxMemPool& EnsureMemPool(const util::Ref& context); ChainstateManager& EnsureChainman(const util::Ref& context); +CBlockPolicyEstimator& EnsureFeeEstimator(const util::Ref& context); #endif diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 3c432464f2..d1eb849b7e 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -41,6 +41,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendtoaddress", 5 , "replaceable" }, { "sendtoaddress", 6 , "conf_target" }, { "sendtoaddress", 8, "avoid_reuse" }, + { "sendtoaddress", 9, "fee_rate"}, + { "sendtoaddress", 10, "verbose"}, { "settxfee", 0, "amount" }, { "sethdseed", 0, "newkeypool" }, { "getreceivedbyaddress", 1, "minconf" }, @@ -72,6 +74,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "sendmany", 4, "subtractfeefrom" }, { "sendmany", 5 , "replaceable" }, { "sendmany", 6 , "conf_target" }, + { "sendmany", 8, "fee_rate"}, + { "sendmany", 9, "verbose" }, { "deriveaddresses", 1, "range" }, { "scantxoutset", 1, "scanobjects" }, { "addmultisigaddress", 0, "nrequired" }, @@ -127,7 +131,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "lockunspent", 1, "transactions" }, { "send", 0, "outputs" }, { "send", 1, "conf_target" }, - { "send", 3, "options" }, + { "send", 3, "fee_rate"}, + { "send", 4, "options" }, { "importprivkey", 2, "rescan" }, { "importaddress", 2, "rescan" }, { "importaddress", 3, "p2sh" }, @@ -205,14 +210,9 @@ public: CRPCConvertTable::CRPCConvertTable() { - const unsigned int n_elem = - (sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0])); - - for (unsigned int i = 0; i < n_elem; i++) { - members.insert(std::make_pair(vRPCConvertParams[i].methodName, - vRPCConvertParams[i].paramIdx)); - membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName, - vRPCConvertParams[i].paramName)); + for (const auto& cp : vRPCConvertParams) { + members.emplace(cp.methodName, cp.paramIdx); + membersByName.emplace(cp.methodName, cp.paramName); } } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index b04e106b2d..c723f1d7ea 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -242,12 +242,7 @@ static RPCHelpMan generatetodescriptor() static RPCHelpMan generate() { return RPCHelpMan{"generate", "has been replaced by the -generate cli option. Refer to -help for more information.", {}, {}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - - if (request.fHelp) { - throw std::runtime_error(self.ToString()); - } else { throw JSONRPCError(RPC_METHOD_NOT_FOUND, self.ToString()); - } }}; } @@ -352,7 +347,7 @@ static RPCHelpMan generateblock() txs.push_back(MakeTransactionRef(std::move(mtx))); } else { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Transaction decode failed for %s", str)); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Transaction decode failed for %s. Make sure the tx has at least one input.", str)); } } @@ -414,7 +409,7 @@ static RPCHelpMan getmininginfo() {RPCResult::Type::NUM, "difficulty", "The current difficulty"}, {RPCResult::Type::NUM, "networkhashps", "The network hashes per second"}, {RPCResult::Type::NUM, "pooledtx", "The size of the mempool"}, - {RPCResult::Type::STR, "chain", "current network name (main, test, regtest)"}, + {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"}, {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"}, }}, RPCExamples{ @@ -663,11 +658,15 @@ static RPCHelpMan getblocktemplate() if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - if (node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) - throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!"); + if (!Params().IsTestChain()) { + if (node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) { + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!"); + } - if (::ChainstateActive().IsInitialBlockDownload()) - throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); + if (::ChainstateActive().IsInitialBlockDownload()) { + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); + } + } static unsigned int nTransactionsUpdatedLast; const CTxMemPool& mempool = EnsureMemPool(request.context); @@ -719,6 +718,13 @@ static RPCHelpMan getblocktemplate() // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? } + const Consensus::Params& consensusParams = Params().GetConsensus(); + + // GBT must be called with 'signet' set in the rules for signet chains + if (consensusParams.signet_blocks && setClientRules.count("signet") != 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the signet rule set (call with {\"rules\": [\"segwit\", \"signet\"]})"); + } + // GBT must be called with 'segwit' set in the rules if (setClientRules.count("segwit") != 1) { throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the segwit rule set (call with {\"rules\": [\"segwit\"]})"); @@ -750,7 +756,6 @@ static RPCHelpMan getblocktemplate() } CHECK_NONFATAL(pindexPrev); CBlock* pblock = &pblocktemplate->block; // pointer for convenience - const Consensus::Params& consensusParams = Params().GetConsensus(); // Update nTime UpdateTime(pblock, consensusParams, pindexPrev); @@ -814,6 +819,12 @@ static RPCHelpMan getblocktemplate() UniValue aRules(UniValue::VARR); aRules.push_back("csv"); if (!fPreSegWit) aRules.push_back("!segwit"); + if (consensusParams.signet_blocks) { + // indicate to miner that they must understand signet rules + // when attempting to mine with this template + aRules.push_back("!signet"); + } + UniValue vbavailable(UniValue::VOBJ); for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) { Consensus::DeploymentPos pos = Consensus::DeploymentPos(j); @@ -894,6 +905,10 @@ static RPCHelpMan getblocktemplate() result.pushKV("bits", strprintf("%08x", pblock->nBits)); result.pushKV("height", (int64_t)(pindexPrev->nHeight+1)); + if (consensusParams.signet_blocks) { + result.pushKV("signet_challenge", HexStr(consensusParams.signet_challenge)); + } + if (!pblocktemplate->vchCoinbaseCommitment.empty()) { result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment)); } @@ -1027,21 +1042,19 @@ static RPCHelpMan submitheader() static RPCHelpMan estimatesmartfee() { return RPCHelpMan{"estimatesmartfee", - "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within conf_target blocks if possible and return the number of blocks\n" - "for which the estimate is valid. Uses virtual transaction size as defined\n" - "in BIP 141 (witness data is discounted).\n", - { - {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, - {"estimate_mode", RPCArg::Type::STR, /* default */ "CONSERVATIVE", "The fee estimate mode.\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within conf_target blocks if possible and return the number of blocks\n" + "for which the estimate is valid. Uses virtual transaction size as defined\n" + "in BIP 141 (witness data is discounted).\n", + { + {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"}, + {"estimate_mode", RPCArg::Type::STR, /* default */ "conservative", "The fee estimate mode.\n" " Whether to return a more conservative estimate which also satisfies\n" " a longer history. A conservative estimate potentially returns a\n" " higher feerate and is more likely to be sufficient for the desired\n" " target, but is not as responsive to short term drops in the\n" - " prevailing fee market. Must be one of:\n" - " \"UNSET\"\n" - " \"ECONOMICAL\"\n" - " \"CONSERVATIVE\""}, + " prevailing fee market. Must be one of (case insensitive):\n" + "\"" + FeeModes("\"\n\"") + "\""}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -1064,13 +1077,16 @@ static RPCHelpMan estimatesmartfee() { RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR}); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); - unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); + + CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context); + + unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); bool conservative = true; if (!request.params[1].isNull()) { FeeEstimateMode fee_mode; if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter"); + throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage()); } if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false; } @@ -1078,7 +1094,7 @@ static RPCHelpMan estimatesmartfee() UniValue result(UniValue::VOBJ); UniValue errors(UniValue::VARR); FeeCalculation feeCalc; - CFeeRate feeRate = ::feeEstimator.estimateSmartFee(conf_target, &feeCalc, conservative); + CFeeRate feeRate = fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative); if (feeRate != CFeeRate(0)) { result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK())); } else { @@ -1149,7 +1165,10 @@ static RPCHelpMan estimaterawfee() { RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); - unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); + + CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context); + + unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); double threshold = 0.95; if (!request.params[1].isNull()) { @@ -1161,14 +1180,14 @@ static RPCHelpMan estimaterawfee() UniValue result(UniValue::VOBJ); - for (const FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) { + for (const FeeEstimateHorizon horizon : ALL_FEE_ESTIMATE_HORIZONS) { CFeeRate feeRate; EstimationResult buckets; // Only output results for horizons which track the target - if (conf_target > ::feeEstimator.HighestTargetTracked(horizon)) continue; + if (conf_target > fee_estimator.HighestTargetTracked(horizon)) continue; - feeRate = ::feeEstimator.estimateRawFee(conf_target, threshold, horizon, &buckets); + feeRate = fee_estimator.estimateRawFee(conf_target, threshold, horizon, &buckets); UniValue horizon_result(UniValue::VOBJ); UniValue errors(UniValue::VARR); UniValue passbucket(UniValue::VOBJ); @@ -1213,24 +1232,24 @@ void RegisterMiningRPCCommands(CRPCTable &t) { // clang-format off static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "mining", "getnetworkhashps", &getnetworkhashps, {"nblocks","height"} }, - { "mining", "getmininginfo", &getmininginfo, {} }, - { "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} }, - { "mining", "getblocktemplate", &getblocktemplate, {"template_request"} }, - { "mining", "submitblock", &submitblock, {"hexdata","dummy"} }, - { "mining", "submitheader", &submitheader, {"hexdata"} }, +{ // category actor (function) + // --------------------- ----------------------- + { "mining", &getnetworkhashps, }, + { "mining", &getmininginfo, }, + { "mining", &prioritisetransaction, }, + { "mining", &getblocktemplate, }, + { "mining", &submitblock, }, + { "mining", &submitheader, }, - { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} }, - { "generating", "generatetodescriptor", &generatetodescriptor, {"num_blocks","descriptor","maxtries"} }, - { "generating", "generateblock", &generateblock, {"output","transactions"} }, + { "generating", &generatetoaddress, }, + { "generating", &generatetodescriptor, }, + { "generating", &generateblock, }, - { "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} }, + { "util", &estimatesmartfee, }, - { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} }, - { "hidden", "generate", &generate, {} }, + { "hidden", &estimaterawfee, }, + { "hidden", &generate, }, }; // clang-format on for (const auto& c : commands) { diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 0c982317f5..b75a7b8d26 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -39,13 +39,14 @@ static RPCHelpMan validateaddress() RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."}, + {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"}, {RPCResult::Type::STR, "address", "The bitcoin address validated"}, {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address"}, {RPCResult::Type::BOOL, "isscript", "If the key is a script"}, {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address"}, {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"}, {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"}, + {RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"}, } }, RPCExamples{ @@ -54,13 +55,14 @@ static RPCHelpMan validateaddress() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - CTxDestination dest = DecodeDestination(request.params[0].get_str()); - bool isValid = IsValidDestination(dest); + std::string error_msg; + CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg); + const bool isValid = IsValidDestination(dest); + CHECK_NONFATAL(isValid == error_msg.empty()); UniValue ret(UniValue::VOBJ); ret.pushKV("isvalid", isValid); - if (isValid) - { + if (isValid) { std::string currentAddress = EncodeDestination(dest); ret.pushKV("address", currentAddress); @@ -69,7 +71,10 @@ static RPCHelpMan validateaddress() UniValue detail = DescribeAddress(dest); ret.pushKVs(detail); + } else { + ret.pushKV("error", error_msg); } + return ret; }, }; @@ -624,8 +629,6 @@ static RPCHelpMan echo(const std::string& name) RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - if (request.fHelp) throw std::runtime_error(self.ToString()); - if (request.params[9].isStr()) { CHECK_NONFATAL(request.params[9].get_str() != "trigger_internal_bug"); } @@ -696,23 +699,23 @@ void RegisterMiscRPCCommands(CRPCTable &t) { // clang-format off static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} }, - { "control", "logging", &logging, {"include", "exclude"}}, - { "util", "validateaddress", &validateaddress, {"address"} }, - { "util", "createmultisig", &createmultisig, {"nrequired","keys","address_type"} }, - { "util", "deriveaddresses", &deriveaddresses, {"descriptor", "range"} }, - { "util", "getdescriptorinfo", &getdescriptorinfo, {"descriptor"} }, - { "util", "verifymessage", &verifymessage, {"address","signature","message"} }, - { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} }, - { "util", "getindexinfo", &getindexinfo, {"index_name"} }, +{ // category actor (function) + // --------------------- ------------------------ + { "control", &getmemoryinfo, }, + { "control", &logging, }, + { "util", &validateaddress, }, + { "util", &createmultisig, }, + { "util", &deriveaddresses, }, + { "util", &getdescriptorinfo, }, + { "util", &verifymessage, }, + { "util", &signmessagewithprivkey, }, + { "util", &getindexinfo, }, /* Not shown in help */ - { "hidden", "setmocktime", &setmocktime, {"timestamp"}}, - { "hidden", "mockscheduler", &mockscheduler, {"delta_time"}}, - { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, - { "hidden", "echojson", &echojson, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, + { "hidden", &setmocktime, }, + { "hidden", &mockscheduler, }, + { "hidden", &echo, }, + { "hidden", &echojson, }, }; // clang-format on for (const auto& c : commands) { diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index def21b119e..47d77b341a 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -5,6 +5,7 @@ #include <rpc/server.h> #include <banman.h> +#include <chainparams.h> #include <clientversion.h> #include <core_io.h> #include <net.h> @@ -29,6 +30,15 @@ #include <univalue.h> +const std::vector<std::string> CONNECTION_TYPE_DOC{ + "outbound-full-relay (default automatic connections)", + "block-relay-only (does not relay transactions or addresses)", + "inbound (initiated by the peer)", + "manual (added via addnode RPC or -addnode/-connect configuration options)", + "addr-fetch (short-lived automatic connection for soliciting addresses)", + "feeler (short-lived automatic connection for testing addresses)" +}; + static RPCHelpMan getconnectioncount() { return RPCHelpMan{"getconnectioncount", @@ -94,6 +104,7 @@ static RPCHelpMan getpeerinfo() {RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"}, {RPCResult::Type::STR, "addrbind", "(ip:port) Bind address of the connection to the peer"}, {RPCResult::Type::STR, "addrlocal", "(ip:port) Local address as reported by the peer"}, + {RPCResult::Type::STR, "network", "Network (ipv4, ipv6, or onion) the peer connected through"}, {RPCResult::Type::NUM, "mapped_as", "The AS in the BGP route to the peer used for diversifying\n" "peer selection (only available if the asmap config flag is set)"}, {RPCResult::Type::STR_HEX, "services", "The services offered"}, @@ -116,18 +127,19 @@ static RPCHelpMan getpeerinfo() {RPCResult::Type::NUM, "version", "The peer version, such as 70001"}, {RPCResult::Type::STR, "subver", "The string version"}, {RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"}, - {RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n" - "(DEPRECATED, returned only if the config option -deprecatedrpc=getpeerinfo_addnode is passed)"}, - {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + "."}, + {RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"}, + {RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"}, {RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"}, - {RPCResult::Type::NUM, "banscore", "The ban score (DEPRECATED, returned only if config option -deprecatedrpc=banscore is passed)"}, {RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"}, {RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"}, {RPCResult::Type::ARR, "inflight", "", { {RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"}, }}, - {RPCResult::Type::BOOL, "whitelisted", "Whether the peer is whitelisted"}, + {RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer", + { + {RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"}, + }}, {RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"}, {RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "", { @@ -139,8 +151,12 @@ static RPCHelpMan getpeerinfo() { {RPCResult::Type::NUM, "msg", "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+"'."} + "Only known message types can appear as keys in the object and all bytes received\n" + "of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."} }}, + {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n" + "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n" + "best capture connection behaviors."}, }}, }}, }, @@ -151,8 +167,9 @@ static RPCHelpMan getpeerinfo() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { NodeContext& node = EnsureNodeContext(request.context); - if(!node.connman) + if(!node.connman || !node.peerman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } std::vector<CNodeStats> vstats; node.connman->GetNodeStats(vstats); @@ -162,13 +179,16 @@ static RPCHelpMan getpeerinfo() for (const CNodeStats& stats : vstats) { UniValue obj(UniValue::VOBJ); CNodeStateStats statestats; - bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); + bool fStateStats = node.peerman->GetNodeStateStats(stats.nodeid, statestats); obj.pushKV("id", stats.nodeid); obj.pushKV("addr", stats.addrName); - if (!(stats.addrLocal.empty())) - obj.pushKV("addrlocal", stats.addrLocal); - if (stats.addrBind.IsValid()) + if (stats.addrBind.IsValid()) { obj.pushKV("addrbind", stats.addrBind.ToString()); + } + if (!(stats.addrLocal.empty())) { + obj.pushKV("addrlocal", stats.addrLocal); + } + obj.pushKV("network", GetNetworkName(stats.m_network)); if (stats.m_mapped_as != 0) { obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as)); } @@ -198,16 +218,10 @@ static RPCHelpMan getpeerinfo() // their ver message. obj.pushKV("subver", stats.cleanSubVer); obj.pushKV("inbound", stats.fInbound); - if (IsDeprecatedRPCEnabled("getpeerinfo_addnode")) { - // addnode is deprecated in v0.21 for removal in v0.22 - obj.pushKV("addnode", stats.m_manual_connection); - } - obj.pushKV("startingheight", stats.nStartingHeight); + obj.pushKV("bip152_hb_to", stats.m_bip152_highbandwidth_to); + obj.pushKV("bip152_hb_from", stats.m_bip152_highbandwidth_from); if (fStateStats) { - if (IsDeprecatedRPCEnabled("banscore")) { - // banscore is deprecated in v0.21 for removal in v0.22 - obj.pushKV("banscore", statestats.m_misbehavior_score); - } + obj.pushKV("startingheight", statestats.m_starting_height); obj.pushKV("synced_headers", statestats.nSyncHeight); obj.pushKV("synced_blocks", statestats.nCommonHeight); UniValue heights(UniValue::VARR); @@ -216,7 +230,6 @@ static RPCHelpMan getpeerinfo() } obj.pushKV("inflight", heights); } - obj.pushKV("whitelisted", stats.m_legacyWhitelisted); UniValue permissions(UniValue::VARR); for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) { permissions.push_back(permission); @@ -237,7 +250,7 @@ static RPCHelpMan getpeerinfo() recvPerMsgCmd.pushKV(i.first, i.second); } obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd); - obj.pushKV("connection_type", stats.m_conn_type_string); + obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type)); ret.push_back(obj); } @@ -268,10 +281,10 @@ static RPCHelpMan addnode() std::string strCommand; if (!request.params[1].isNull()) strCommand = request.params[1].get_str(); - if (request.fHelp || request.params.size() != 2 || - (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) + if (strCommand != "onetry" && strCommand != "add" && strCommand != "remove") { throw std::runtime_error( self.ToString()); + } NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) @@ -302,6 +315,61 @@ static RPCHelpMan addnode() }; } +static RPCHelpMan addconnection() +{ + return RPCHelpMan{"addconnection", + "\nOpen an outbound connection to a specified node. This RPC is for testing only.\n", + { + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."}, + {"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open, either \"outbound-full-relay\" or \"block-relay-only\"."}, + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + { RPCResult::Type::STR, "address", "Address of newly added connection." }, + { RPCResult::Type::STR, "connection_type", "Type of connection opened." }, + }}, + RPCExamples{ + HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"") + + HelpExampleRpc("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { + throw std::runtime_error("addconnection is for regression testing (-regtest mode) only."); + } + + RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR}); + const std::string address = request.params[0].get_str(); + const std::string conn_type_in{TrimString(request.params[1].get_str())}; + ConnectionType conn_type{}; + if (conn_type_in == "outbound-full-relay") { + conn_type = ConnectionType::OUTBOUND_FULL_RELAY; + } else if (conn_type_in == "block-relay-only") { + conn_type = ConnectionType::BLOCK_RELAY; + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString()); + } + + NodeContext& node = EnsureNodeContext(request.context); + if (!node.connman) { + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled."); + } + + const bool success = node.connman->AddConnection(address, conn_type); + if (!success) { + throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type."); + } + + UniValue info(UniValue::VOBJ); + info.pushKV("address", address); + info.pushKV("connection_type", conn_type_in); + + return info; +}, + }; +} + static RPCHelpMan disconnectnode() { return RPCHelpMan{"disconnectnode", @@ -462,12 +530,12 @@ static RPCHelpMan getnettotals() obj.pushKV("timemillis", GetTimeMillis()); UniValue outboundLimit(UniValue::VOBJ); - outboundLimit.pushKV("timeframe", node.connman->GetMaxOutboundTimeframe()); + outboundLimit.pushKV("timeframe", count_seconds(node.connman->GetMaxOutboundTimeframe())); outboundLimit.pushKV("target", node.connman->GetMaxOutboundTarget()); outboundLimit.pushKV("target_reached", node.connman->OutboundTargetReached(false)); outboundLimit.pushKV("serve_historical_blocks", !node.connman->OutboundTargetReached(true)); outboundLimit.pushKV("bytes_left_in_cycle", node.connman->GetOutboundTargetBytesLeft()); - outboundLimit.pushKV("time_left_in_cycle", node.connman->GetMaxOutboundTimeLeftInCycle()); + outboundLimit.pushKV("time_left_in_cycle", count_seconds(node.connman->GetMaxOutboundTimeLeftInCycle())); obj.pushKV("uploadtarget", outboundLimit); return obj; }, @@ -477,11 +545,9 @@ static RPCHelpMan getnettotals() static UniValue GetNetworksInfo() { UniValue networks(UniValue::VARR); - for(int n=0; n<NET_MAX; ++n) - { + for (int n = 0; n < NET_MAX; ++n) { enum Network network = static_cast<enum Network>(n); - if(network == NET_UNROUTABLE || network == NET_INTERNAL) - continue; + if (network == NET_UNROUTABLE || network == NET_I2P || network == NET_CJDNS || network == NET_INTERNAL) continue; proxyType proxy; UniValue obj(UniValue::VOBJ); GetProxy(network, proxy); @@ -559,7 +625,9 @@ static RPCHelpMan getnetworkinfo() obj.pushKV("localservices", strprintf("%016x", services)); obj.pushKV("localservicesnames", GetServicesNames(services)); } - obj.pushKV("localrelay", g_relay_txes); + if (node.peerman) { + obj.pushKV("localrelay", !node.peerman->IgnoresIncomingTxs()); + } obj.pushKV("timeoffset", GetTimeOffset()); if (node.connman) { obj.pushKV("networkactive", node.connman->GetNetworkActive()); @@ -610,7 +678,7 @@ static RPCHelpMan setban() std::string strCommand; if (!request.params[1].isNull()) strCommand = request.params[1].get_str(); - if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || (strCommand != "add" && strCommand != "remove")) { + if (strCommand != "add" && strCommand != "remove") { throw std::runtime_error(help.ToString()); } NodeContext& node = EnsureNodeContext(request.context); @@ -873,22 +941,24 @@ void RegisterNetRPCCommands(CRPCTable &t) { // clang-format off static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "network", "getconnectioncount", &getconnectioncount, {} }, - { "network", "ping", &ping, {} }, - { "network", "getpeerinfo", &getpeerinfo, {} }, - { "network", "addnode", &addnode, {"node","command"} }, - { "network", "disconnectnode", &disconnectnode, {"address", "nodeid"} }, - { "network", "getaddednodeinfo", &getaddednodeinfo, {"node"} }, - { "network", "getnettotals", &getnettotals, {} }, - { "network", "getnetworkinfo", &getnetworkinfo, {} }, - { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} }, - { "network", "listbanned", &listbanned, {} }, - { "network", "clearbanned", &clearbanned, {} }, - { "network", "setnetworkactive", &setnetworkactive, {"state"} }, - { "network", "getnodeaddresses", &getnodeaddresses, {"count"} }, - { "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} }, +{ // category actor + // --------------------- ----------------------- + { "network", &getconnectioncount, }, + { "network", &ping, }, + { "network", &getpeerinfo, }, + { "network", &addnode, }, + { "network", &disconnectnode, }, + { "network", &getaddednodeinfo, }, + { "network", &getnettotals, }, + { "network", &getnetworkinfo, }, + { "network", &setban, }, + { "network", &listbanned, }, + { "network", &clearbanned, }, + { "network", &setnetworkactive, }, + { "network", &getnodeaddresses, }, + + { "hidden", &addconnection, }, + { "hidden", &addpeeraddress, }, }; // clang-format on for (const auto& c : commands) { diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index d1475f452d..fc00a1efad 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -62,6 +62,7 @@ enum RPCErrorCode RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found + RPC_CLIENT_NODE_CAPACITY_REACHED= -34, //!< Max number of outbound or block-relay connections already open //! Chain errors RPC_CLIENT_MEMPOOL_DISABLED = -33, //!< No mempool instance found @@ -78,6 +79,7 @@ enum RPCErrorCode RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked RPC_WALLET_NOT_FOUND = -18, //!< Invalid wallet specified RPC_WALLET_NOT_SPECIFIED = -19, //!< No wallet specified (error when there are multiple wallets loaded) + RPC_WALLET_ALREADY_LOADED = -35, //!< This same wallet is already loaded //! Backwards compatible aliases RPC_WALLET_INVALID_ACCOUNT_NAME = RPC_WALLET_INVALID_LABEL_NAME, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index e60e0a2d90..031ed31da1 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -109,7 +109,7 @@ static RPCHelpMan getrawtransaction() {RPCResult::Type::OBJ, "", "", { {RPCResult::Type::STR_HEX, "txid", "The transaction id"}, - {RPCResult::Type::STR, "vout", ""}, + {RPCResult::Type::NUM, "vout", "The output number"}, {RPCResult::Type::OBJ, "scriptSig", "The script", { {RPCResult::Type::STR, "asm", "asm"}, @@ -244,16 +244,15 @@ static RPCHelpMan gettxoutproof() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::set<uint256> setTxids; - uint256 oneTxid; UniValue txids = request.params[0].get_array(); + if (txids.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txids' cannot be empty"); + } for (unsigned int idx = 0; idx < txids.size(); idx++) { - const UniValue& txid = txids[idx]; - uint256 hash(ParseHashV(txid, "txid")); - if (setTxids.count(hash)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txid.get_str()); + auto ret = setTxids.insert(ParseHashV(txids[idx], "txid")); + if (!ret.second) { + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txids[idx].get_str()); } - setTxids.insert(hash); - oneTxid = hash; } CBlockIndex* pblockindex = nullptr; @@ -287,7 +286,7 @@ static RPCHelpMan gettxoutproof() LOCK(cs_main); if (pblockindex == nullptr) { - const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, oneTxid, Params().GetConsensus(), hashBlock); + const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, *setTxids.begin(), Params().GetConsensus(), hashBlock); if (!tx || hashBlock.IsNull()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); } @@ -656,8 +655,8 @@ static RPCHelpMan combinerawtransaction() std::vector<CMutableTransaction> txVariants(txs.size()); for (unsigned int idx = 0; idx < txs.size(); idx++) { - if (!DecodeHexTx(txVariants[idx], txs[idx].get_str(), true)) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d", idx)); + if (!DecodeHexTx(txVariants[idx], txs[idx].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d. Make sure the tx has at least one input.", idx)); } } @@ -780,8 +779,8 @@ static RPCHelpMan signrawtransactionwithkey() RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); CMutableTransaction mtx; - if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(mtx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); } FillableSigningProvider keystore; @@ -847,10 +846,10 @@ static RPCHelpMan sendrawtransaction() UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() }); - // parse hex string from parameter CMutableTransaction mtx; - if (!DecodeHexTx(mtx, request.params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(mtx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); + } CTransactionRef tx(MakeTransactionRef(std::move(mtx))); const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? @@ -895,6 +894,7 @@ static RPCHelpMan testmempoolaccept() {RPCResult::Type::OBJ, "", "", { {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"}, + {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"}, {RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"}, {RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"}, {RPCResult::Type::OBJ, "fees", "Transaction fees (only present if 'allowed' is true)", @@ -928,10 +928,9 @@ static RPCHelpMan testmempoolaccept() CMutableTransaction mtx; if (!DecodeHexTx(mtx, request.params[0].get_array()[0].get_str())) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); } CTransactionRef tx(MakeTransactionRef(std::move(mtx))); - const uint256& tx_hash = tx->GetHash(); const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ? DEFAULT_MAX_RAW_TX_FEE_RATE : @@ -943,15 +942,24 @@ static RPCHelpMan testmempoolaccept() UniValue result(UniValue::VARR); UniValue result_0(UniValue::VOBJ); - result_0.pushKV("txid", tx_hash.GetHex()); + result_0.pushKV("txid", tx->GetHash().GetHex()); + result_0.pushKV("wtxid", tx->GetWitnessHash().GetHex()); TxValidationState state; bool test_accept_res; - CAmount fee; + CAmount fee{0}; { LOCK(cs_main); test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx), - nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accept */ true, &fee); + nullptr /* plTxnReplaced */, false /* bypass_limits */, /* test_accept */ true, &fee); + } + + // Check that fee does not exceed maximum fee + if (test_accept_res && max_raw_tx_fee && fee > max_raw_tx_fee) { + result_0.pushKV("allowed", false); + result_0.pushKV("reject-reason", "max-fee-exceeded"); + result.push_back(std::move(result_0)); + return result; } result_0.pushKV("allowed", test_accept_res); @@ -1851,27 +1859,27 @@ void RegisterRawTransactionRPCCommands(CRPCTable &t) { // clang-format off static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose","blockhash"} }, - { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} }, - { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring","iswitness"} }, - { "rawtransactions", "decodescript", &decodescript, {"hexstring"} }, - { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","maxfeerate"} }, - { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} }, - { "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} }, - { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","maxfeerate"} }, - { "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} }, - { "rawtransactions", "combinepsbt", &combinepsbt, {"txs"} }, - { "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} }, - { "rawtransactions", "createpsbt", &createpsbt, {"inputs","outputs","locktime","replaceable"} }, - { "rawtransactions", "converttopsbt", &converttopsbt, {"hexstring","permitsigdata","iswitness"} }, - { "rawtransactions", "utxoupdatepsbt", &utxoupdatepsbt, {"psbt", "descriptors"} }, - { "rawtransactions", "joinpsbts", &joinpsbts, {"txs"} }, - { "rawtransactions", "analyzepsbt", &analyzepsbt, {"psbt"} }, - - { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, - { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, +{ // category actor (function) + // --------------------- ----------------------- + { "rawtransactions", &getrawtransaction, }, + { "rawtransactions", &createrawtransaction, }, + { "rawtransactions", &decoderawtransaction, }, + { "rawtransactions", &decodescript, }, + { "rawtransactions", &sendrawtransaction, }, + { "rawtransactions", &combinerawtransaction, }, + { "rawtransactions", &signrawtransactionwithkey, }, + { "rawtransactions", &testmempoolaccept, }, + { "rawtransactions", &decodepsbt, }, + { "rawtransactions", &combinepsbt, }, + { "rawtransactions", &finalizepsbt, }, + { "rawtransactions", &createpsbt, }, + { "rawtransactions", &converttopsbt, }, + { "rawtransactions", &utxoupdatepsbt, }, + { "rawtransactions", &joinpsbts, }, + { "rawtransactions", &analyzepsbt, }, + + { "blockchain", &gettxoutproof, }, + { "blockchain", &verifytxoutproof, }, }; // clang-format on for (const auto& c : commands) { diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 8dfbead0e4..122a92f084 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -55,7 +55,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); int nOutput = vout_v.get_int(); if (nOutput < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); uint32_t nSequence; if (rbf) { @@ -177,7 +177,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst int nOut = find_value(prevOut, "vout").get_int(); if (nOut < 0) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout cannot be negative"); } COutPoint out(txid, nOut); @@ -286,7 +286,7 @@ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, SignTransactionResultToJSON(mtx, complete, coins, input_errors, result); } -void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, std::map<int, std::string>& input_errors, UniValue& result) +void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, std::string>& input_errors, UniValue& result) { // Make errors UniValue UniValue vErrors(UniValue::VARR); diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h index 942314eccf..ce7d5834fa 100644 --- a/src/rpc/rawtransaction_util.h +++ b/src/rpc/rawtransaction_util.h @@ -25,7 +25,7 @@ class SigningProvider; * @param result JSON object where signed transaction results accumulate */ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map<COutPoint, Coin>& coins, const UniValue& hashType, UniValue& result); -void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, std::map<int, std::string>& input_errors, UniValue& result); +void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map<COutPoint, Coin>& coins, const std::map<int, std::string>& input_errors, UniValue& result); /** * Parse a prevtxs UniValue array and get the map of coins from it diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index d9ad70fa37..a7866474e1 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/rpc/request.h b/src/rpc/request.h index 4761e9e371..de3a4ae840 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,7 +40,7 @@ public: std::string peerAddr; const util::Ref& context; - JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), fHelp(false), context(context) {} + explicit JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), fHelp(false), context(context) {} //! Initializes request information from another request object and the //! given context. The implementation should be updated if any members are diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index f32d9abac6..9a9b3713f3 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -144,8 +144,13 @@ static RPCHelpMan help() [&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue { std::string strCommand; - if (jsonRequest.params.size() > 0) + if (jsonRequest.params.size() > 0) { strCommand = jsonRequest.params[0].get_str(); + } + if (strCommand == "dump_all_command_conversions") { + // Used for testing only, undocumented + return tableRPC.dumpArgMap(); + } return tableRPC.help(strCommand, jsonRequest); }, @@ -244,13 +249,13 @@ static RPCHelpMan getrpcinfo() // clang-format off static const CRPCCommand vRPCCommands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- +{ // category actor (function) + // --------------------- ----------------------- /* Overall control/query calls */ - { "control", "getrpcinfo", &getrpcinfo, {} }, - { "control", "help", &help, {"command"} }, - { "control", "stop", &stop, {"wait"} }, - { "control", "uptime", &uptime, {} }, + { "control", &getrpcinfo, }, + { "control", &help, }, + { "control", &stop, }, + { "control", &uptime, }, }; // clang-format on @@ -479,6 +484,18 @@ std::vector<std::string> CRPCTable::listCommands() const return commandList; } +UniValue CRPCTable::dumpArgMap() const +{ + UniValue ret{UniValue::VARR}; + for (const auto& cmd : mapCommands) { + for (const auto& c : cmd.second) { + const auto help = RpcMethodFnType(c->unique_id)(); + help.AppendArgMap(ret); + } + } + return ret; +} + void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface) { if (!timerInterface) diff --git a/src/rpc/server.h b/src/rpc/server.h index b2358ac5b2..fe5a791e1e 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -85,7 +85,6 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface); */ void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nSeconds); -typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest); typedef RPCHelpMan (*RpcMethodFnType)(); class CRPCCommand @@ -104,7 +103,7 @@ public: } //! Simplified constructor taking plain RpcMethodFnType function pointer. - CRPCCommand(std::string category, std::string name_in, RpcMethodFnType fn, std::vector<std::string> args_in) + CRPCCommand(std::string category, RpcMethodFnType fn) : CRPCCommand( category, fn().m_name, @@ -112,16 +111,6 @@ public: fn().GetArgNames(), intptr_t(fn)) { - CHECK_NONFATAL(fn().m_name == name_in); - CHECK_NONFATAL(fn().GetArgNames() == args_in); - } - - //! Simplified constructor taking plain rpcfn_type function pointer. - CRPCCommand(const char* category, const char* name, rpcfn_type fn, std::initializer_list<const char*> args) - : CRPCCommand(category, name, - [fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn(request); return true; }, - {args.begin(), args.end()}, intptr_t(fn)) - { } std::string category; @@ -156,6 +145,10 @@ public: */ std::vector<std::string> listCommands() const; + /** + * Return all named arguments that need to be converted by the client from string to another JSON type + */ + UniValue dumpArgMap() const; /** * Appends a CRPCCommand to the dispatch table. diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 40dfdb587e..bfdba5253c 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -209,7 +209,7 @@ CTxDestination AddAndGetMultisigDestination(const int required, const std::vecto return dest; } -class DescribeAddressVisitor : public boost::static_visitor<UniValue> +class DescribeAddressVisitor { public: explicit DescribeAddressVisitor() {} @@ -267,16 +267,17 @@ public: UniValue DescribeAddress(const CTxDestination& dest) { - return boost::apply_visitor(DescribeAddressVisitor(), dest); + return std::visit(DescribeAddressVisitor(), dest); } unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target) { - int target = value.get_int(); - if (target < 1 || (unsigned int)target > max_target) { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u - %u", 1, max_target)); + const int target{value.get_int()}; + const unsigned int unsigned_target{static_cast<unsigned int>(target)}; + if (target < 1 || unsigned_target > max_target) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid conf_target, must be between %u and %u", 1, max_target)); } - return (unsigned int)target; + return unsigned_target; } RPCErrorCode RPCErrorFromTransactionError(TransactionError terr) @@ -548,6 +549,24 @@ std::string RPCHelpMan::ToString() const return ret; } +void RPCHelpMan::AppendArgMap(UniValue& arr) const +{ + for (int i{0}; i < int(m_args.size()); ++i) { + const auto& arg = m_args.at(i); + std::vector<std::string> arg_names; + boost::split(arg_names, arg.m_names, boost::is_any_of("|")); + for (const auto& arg_name : arg_names) { + UniValue map{UniValue::VARR}; + map.push_back(m_name); + map.push_back(i); + map.push_back(arg_name); + map.push_back(arg.m_type == RPCArg::Type::STR || + arg.m_type == RPCArg::Type::STR_HEX); + arr.push_back(map); + } + } +} + std::string RPCArg::GetFirstName() const { return m_names.substr(0, m_names.find("|")); @@ -561,10 +580,10 @@ std::string RPCArg::GetName() const bool RPCArg::IsOptional() const { - if (m_fallback.which() == 1) { + if (m_fallback.index() == 1) { return true; } else { - return RPCArg::Optional::NO != boost::get<RPCArg::Optional>(m_fallback); + return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback); } } @@ -608,10 +627,10 @@ std::string RPCArg::ToDescriptionString() const } } // no default case, so the compiler can warn about missing cases } - if (m_fallback.which() == 1) { - ret += ", optional, default=" + boost::get<std::string>(m_fallback); + if (m_fallback.index() == 1) { + ret += ", optional, default=" + std::get<std::string>(m_fallback); } else { - switch (boost::get<RPCArg::Optional>(m_fallback)) { + switch (std::get<RPCArg::Optional>(m_fallback)) { case RPCArg::Optional::OMITTED: { // nothing to do. Element is treated as if not present and has no default value break; diff --git a/src/rpc/util.h b/src/rpc/util.h index 45b0bb0c7e..444a013ca1 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-2021 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,10 +19,9 @@ #include <util/check.h> #include <string> +#include <variant> #include <vector> -#include <boost/variant.hpp> - /** * String used to describe UNIX epoch time in documentation, factored out to a * constant for consistency. @@ -144,7 +143,7 @@ struct RPCArg { */ OMITTED, }; - using Fallback = boost::variant<Optional, /* default value for optional args */ std::string>; + using Fallback = std::variant<Optional, /* default value for optional args */ std::string>; const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments) const Type m_type; const bool m_hidden; @@ -337,6 +336,8 @@ public: RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun); std::string ToString() const; + /** Append the named args that need to be converted from string to another JSON type */ + void AppendArgMap(UniValue& arr) const; UniValue HandleRequest(const JSONRPCRequest& request) { Check(request); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 7c361bf26f..b3ee23f139 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -7,6 +7,7 @@ #include <random.h> #include <assert.h> +#include <functional> #include <utility> CScheduler::CScheduler() diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index 15e204062f..76609f01a7 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -16,8 +16,7 @@ namespace { class TxInputStream { public: - TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) : - m_type(nTypeIn), + TxInputStream(int nVersionIn, const unsigned char *txTo, size_t txToLen) : m_version(nVersionIn), m_data(txTo), m_remaining(txToLen) @@ -47,9 +46,7 @@ public: } int GetVersion() const { return m_version; } - int GetType() const { return m_type; } private: - const int m_type; const int m_version; const unsigned char* m_data; size_t m_remaining; @@ -84,7 +81,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP return set_error(err, bitcoinconsensus_ERR_INVALID_FLAGS); } try { - TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen); + TxInputStream stream(PROTOCOL_VERSION, txTo, txToLen); CTransaction tx(deserialize, stream); if (nIn >= tx.vin.size()) return set_error(err, bitcoinconsensus_ERR_TX_INDEX); diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 6c0a98cca2..9e4b8a9dd6 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -156,7 +156,7 @@ protected: uint32_t m_expr_index; public: - PubkeyProvider(uint32_t exp_index) : m_expr_index(exp_index) {} + explicit PubkeyProvider(uint32_t exp_index) : m_expr_index(exp_index) {} virtual ~PubkeyProvider() = default; @@ -565,7 +565,7 @@ public: Optional<OutputType> GetOutputType() const override { - switch (m_destination.which()) { + switch (m_destination.index()) { case 1 /* PKHash */: case 2 /* ScriptHash */: return OutputType::LEGACY; case 3 /* WitnessV0ScriptHash */: @@ -593,7 +593,7 @@ public: { CTxDestination dest; ExtractDestination(m_script, dest); - switch (dest.which()) { + switch (dest.index()) { case 1 /* PKHash */: case 2 /* ScriptHash */: return OutputType::LEGACY; case 3 /* WitnessV0ScriptHash */: @@ -731,7 +731,7 @@ enum class ParseScriptContext { }; /** Parse a key path, being passed a split list of elements (the first element is ignored). */ -NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error) +[[nodiscard]] bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out, std::string& error) { for (size_t i = 1; i < split.size(); ++i) { Span<const char> elem = split[i]; diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 50a6192476..ecac3b9e7e 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -305,8 +305,8 @@ private: uint32_t m_first_false_pos = NO_FALSE; public: - bool empty() { return m_stack_size == 0; } - bool all_true() { return m_first_false_pos == NO_FALSE; } + bool empty() const { return m_stack_size == 0; } + bool all_true() const { return m_first_false_pos == NO_FALSE; } void push_back(bool f) { if (m_first_false_pos == NO_FALSE && !f) { @@ -342,13 +342,10 @@ public: }; } -/** Helper for OP_CHECKSIG and OP_CHECKSIGVERIFY - * - * A return value of false means the script fails entirely. When true is returned, the - * fSuccess variable indicates whether the signature check itself succeeded. - */ -static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess) +static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess) { + assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0); + // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); @@ -363,7 +360,7 @@ static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScrip //serror is set return false; } - fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); + fSuccess = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion); if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); @@ -371,7 +368,67 @@ static bool EvalChecksig(const valtype& vchSig, const valtype& vchPubKey, CScrip return true; } -bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) +static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success) +{ + assert(sigversion == SigVersion::TAPSCRIPT); + + /* + * The following validation sequence is consensus critical. Please note how -- + * upgradable public key versions precede other rules; + * the script execution fails when using empty signature with invalid public key; + * the script execution fails when using non-empty invalid signature. + */ + success = !sig.empty(); + if (success) { + // Implement the sigops/witnesssize ratio test. + // Passing with an upgradable public key version is also counted. + assert(execdata.m_validation_weight_left_init); + execdata.m_validation_weight_left -= VALIDATION_WEIGHT_PER_SIGOP_PASSED; + if (execdata.m_validation_weight_left < 0) { + return set_error(serror, SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT); + } + } + if (pubkey.size() == 0) { + return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); + } else if (pubkey.size() == 32) { + if (success && !checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror)) { + return false; // serror is set + } + } else { + /* + * New public key version softforks should be defined before this `else` block. + * Generally, the new code should not do anything but failing the script execution. To avoid + * consensus bugs, it should not modify any existing values (including `success`). + */ + if ((flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE) != 0) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE); + } + } + + return true; +} + +/** Helper for OP_CHECKSIG, OP_CHECKSIGVERIFY, and (in Tapscript) OP_CHECKSIGADD. + * + * A return value of false means the script fails entirely. When true is returned, the + * success variable indicates whether the signature check itself succeeded. + */ +static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success) +{ + switch (sigversion) { + case SigVersion::BASE: + case SigVersion::WITNESS_V0: + return EvalChecksigPreTapscript(sig, pubkey, pbegincodehash, pend, flags, checker, sigversion, serror, success); + case SigVersion::TAPSCRIPT: + return EvalChecksigTapscript(sig, pubkey, execdata, flags, checker, sigversion, serror, success); + case SigVersion::TAPROOT: + // Key path spending in Taproot has no script, so this is unreachable. + break; + } + assert(false); +} + +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); @@ -381,6 +438,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& // static const valtype vchZero(0); static const valtype vchTrue(1, 1); + // sigversion cannot be TAPROOT here, as it admits no script execution. + assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0 || sigversion == SigVersion::TAPSCRIPT); + CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); @@ -389,15 +449,18 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& ConditionStack vfExec; std::vector<valtype> altstack; set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); - if (script.size() > MAX_SCRIPT_SIZE) + if ((sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) && script.size() > MAX_SCRIPT_SIZE) { return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); + } int nOpCount = 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; + uint32_t opcode_pos = 0; + execdata.m_codeseparator_pos = 0xFFFFFFFFUL; + execdata.m_codeseparator_pos_init = true; try { - while (pc < pend) - { + for (; pc < pend; ++opcode_pos) { bool fExec = vfExec.all_true(); // @@ -408,9 +471,12 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) return set_error(serror, SCRIPT_ERR_PUSH_SIZE); - // Note how OP_RESERVED does not count towards the opcode limit. - if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) - return set_error(serror, SCRIPT_ERR_OP_COUNT); + if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) { + // Note how OP_RESERVED does not count towards the opcode limit. + if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT) { + return set_error(serror, SCRIPT_ERR_OP_COUNT); + } + } if (opcode == OP_CAT || opcode == OP_SUBSTR || @@ -568,6 +634,15 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& if (stack.size() < 1) return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL); valtype& vch = stacktop(-1); + // Tapscript requires minimal IF/NOTIF inputs as a consensus rule. + if (sigversion == SigVersion::TAPSCRIPT) { + // The input argument to the OP_IF and OP_NOTIF opcodes must be either + // exactly 0 (the empty vector) or exactly 1 (the one-byte vector with value 1). + if (vch.size() > 1 || (vch.size() == 1 && vch[0] != 1)) { + return set_error(serror, SCRIPT_ERR_TAPSCRIPT_MINIMALIF); + } + } + // Under witness v0 rules it is only a policy rule, enabled through SCRIPT_VERIFY_MINIMALIF. if (sigversion == SigVersion::WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) { if (vch.size() > 1) return set_error(serror, SCRIPT_ERR_MINIMALIF); @@ -1001,6 +1076,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& // Hash starts after the code separator pbegincodehash = pc; + execdata.m_codeseparator_pos = opcode_pos; } break; @@ -1015,7 +1091,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& valtype& vchPubKey = stacktop(-1); bool fSuccess = true; - if (!EvalChecksig(vchSig, vchPubKey, pbegincodehash, pend, flags, checker, sigversion, serror, fSuccess)) return false; + if (!EvalChecksig(vchSig, vchPubKey, pbegincodehash, pend, execdata, flags, checker, sigversion, serror, fSuccess)) return false; popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); @@ -1029,9 +1105,32 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& } break; + case OP_CHECKSIGADD: + { + // OP_CHECKSIGADD is only available in Tapscript + if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + + // (sig num pubkey -- num) + if (stack.size() < 3) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + const valtype& sig = stacktop(-3); + const CScriptNum num(stacktop(-2), fRequireMinimal); + const valtype& pubkey = stacktop(-1); + + bool success = true; + if (!EvalChecksig(sig, pubkey, pbegincodehash, pend, execdata, flags, checker, sigversion, serror, success)) return false; + popstack(stack); + popstack(stack); + popstack(stack); + stack.push_back((num + (success ? 1 : 0)).getvch()); + } + break; + case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { + if (sigversion == SigVersion::TAPSCRIPT) return set_error(serror, SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG); + // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) int i = 1; @@ -1089,7 +1188,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& } // Check signature - bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); + bool fOk = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion); if (fOk) { isig++; @@ -1159,6 +1258,12 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& return set_success(serror); } +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) +{ + ScriptExecutionData execdata; + return EvalScript(stack, script, flags, checker, sigversion, execdata, serror); +} + namespace { /** @@ -1291,35 +1396,183 @@ uint256 GetOutputsSHA256(const T& txTo) return ss.GetSHA256(); } +/** Compute the (single) SHA256 of the concatenation of all amounts spent by a tx. */ +uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent) +{ + CHashWriter ss(SER_GETHASH, 0); + for (const auto& txout : outputs_spent) { + ss << txout.nValue; + } + return ss.GetSHA256(); +} + +/** Compute the (single) SHA256 of the concatenation of all scriptPubKeys spent by a tx. */ +uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent) +{ + CHashWriter ss(SER_GETHASH, 0); + for (const auto& txout : outputs_spent) { + ss << txout.scriptPubKey; + } + return ss.GetSHA256(); +} + + } // namespace template <class T> -void PrecomputedTransactionData::Init(const T& txTo) +void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent_outputs) { - assert(!m_ready); + assert(!m_spent_outputs_ready); - // Cache is calculated only for transactions with witness - if (txTo.HasWitness()) { - hashPrevouts = SHA256Uint256(GetPrevoutsSHA256(txTo)); - hashSequence = SHA256Uint256(GetSequencesSHA256(txTo)); - hashOutputs = SHA256Uint256(GetOutputsSHA256(txTo)); + m_spent_outputs = std::move(spent_outputs); + if (!m_spent_outputs.empty()) { + assert(m_spent_outputs.size() == txTo.vin.size()); + m_spent_outputs_ready = true; } - m_ready = true; + // Determine which precomputation-impacting features this transaction uses. + bool uses_bip143_segwit = false; + bool uses_bip341_taproot = false; + for (size_t inpos = 0; inpos < txTo.vin.size(); ++inpos) { + if (!txTo.vin[inpos].scriptWitness.IsNull()) { + if (m_spent_outputs_ready && m_spent_outputs[inpos].scriptPubKey.size() == 2 + WITNESS_V1_TAPROOT_SIZE && + m_spent_outputs[inpos].scriptPubKey[0] == OP_1) { + // Treat every witness-bearing spend with 34-byte scriptPubKey that starts with OP_1 as a Taproot + // spend. This only works if spent_outputs was provided as well, but if it wasn't, actual validation + // will fail anyway. Note that this branch may trigger for scriptPubKeys that aren't actually segwit + // but in that case validation will fail as SCRIPT_ERR_WITNESS_UNEXPECTED anyway. + uses_bip341_taproot = true; + } else { + // Treat every spend that's not known to native witness v1 as a Witness v0 spend. This branch may + // also be taken for unknown witness versions, but it is harmless, and being precise would require + // P2SH evaluation to find the redeemScript. + uses_bip143_segwit = true; + } + } + if (uses_bip341_taproot && uses_bip143_segwit) break; // No need to scan further if we already need all. + } + + if (uses_bip143_segwit || uses_bip341_taproot) { + // Computations shared between both sighash schemes. + m_prevouts_single_hash = GetPrevoutsSHA256(txTo); + m_sequences_single_hash = GetSequencesSHA256(txTo); + m_outputs_single_hash = GetOutputsSHA256(txTo); + } + if (uses_bip143_segwit) { + hashPrevouts = SHA256Uint256(m_prevouts_single_hash); + hashSequence = SHA256Uint256(m_sequences_single_hash); + hashOutputs = SHA256Uint256(m_outputs_single_hash); + m_bip143_segwit_ready = true; + } + if (uses_bip341_taproot) { + m_spent_amounts_single_hash = GetSpentAmountsSHA256(m_spent_outputs); + m_spent_scripts_single_hash = GetSpentScriptsSHA256(m_spent_outputs); + m_bip341_taproot_ready = true; + } } template <class T> PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo) { - Init(txTo); + Init(txTo, {}); } // explicit instantiation -template void PrecomputedTransactionData::Init(const CTransaction& txTo); -template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo); +template void PrecomputedTransactionData::Init(const CTransaction& txTo, std::vector<CTxOut>&& spent_outputs); +template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo, std::vector<CTxOut>&& spent_outputs); template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo); template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo); +static const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash"); +static const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf"); +static const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch"); +static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak"); + +template<typename T> +bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache) +{ + uint8_t ext_flag, key_version; + switch (sigversion) { + case SigVersion::TAPROOT: + ext_flag = 0; + // key_version is not used and left uninitialized. + break; + case SigVersion::TAPSCRIPT: + ext_flag = 1; + // key_version must be 0 for now, representing the current version of + // 32-byte public keys in the tapscript signature opcode execution. + // An upgradable public key version (with a size not 32-byte) may + // request a different key_version with a new sigversion. + key_version = 0; + break; + default: + assert(false); + } + assert(in_pos < tx_to.vin.size()); + assert(cache.m_bip341_taproot_ready && cache.m_spent_outputs_ready); + + CHashWriter ss = HASHER_TAPSIGHASH; + + // Epoch + static constexpr uint8_t EPOCH = 0; + ss << EPOCH; + + // Hash type + const uint8_t output_type = (hash_type == SIGHASH_DEFAULT) ? SIGHASH_ALL : (hash_type & SIGHASH_OUTPUT_MASK); // Default (no sighash byte) is equivalent to SIGHASH_ALL + const uint8_t input_type = hash_type & SIGHASH_INPUT_MASK; + if (!(hash_type <= 0x03 || (hash_type >= 0x81 && hash_type <= 0x83))) return false; + ss << hash_type; + + // Transaction level data + ss << tx_to.nVersion; + ss << tx_to.nLockTime; + if (input_type != SIGHASH_ANYONECANPAY) { + ss << cache.m_prevouts_single_hash; + ss << cache.m_spent_amounts_single_hash; + ss << cache.m_spent_scripts_single_hash; + ss << cache.m_sequences_single_hash; + } + if (output_type == SIGHASH_ALL) { + ss << cache.m_outputs_single_hash; + } + + // Data about the input/prevout being spent + assert(execdata.m_annex_init); + const bool have_annex = execdata.m_annex_present; + const uint8_t spend_type = (ext_flag << 1) + (have_annex ? 1 : 0); // The low bit indicates whether an annex is present. + ss << spend_type; + if (input_type == SIGHASH_ANYONECANPAY) { + ss << tx_to.vin[in_pos].prevout; + ss << cache.m_spent_outputs[in_pos]; + ss << tx_to.vin[in_pos].nSequence; + } else { + ss << in_pos; + } + if (have_annex) { + ss << execdata.m_annex_hash; + } + + // Data about the output (if only one). + if (output_type == SIGHASH_SINGLE) { + if (in_pos >= tx_to.vout.size()) return false; + CHashWriter sha_single_output(SER_GETHASH, 0); + sha_single_output << tx_to.vout[in_pos]; + ss << sha_single_output.GetSHA256(); + } + + // Additional data for BIP 342 signatures + if (sigversion == SigVersion::TAPSCRIPT) { + assert(execdata.m_tapleaf_hash_init); + ss << execdata.m_tapleaf_hash; + ss << key_version; + assert(execdata.m_codeseparator_pos_init); + ss << execdata.m_codeseparator_pos; + } + + hash_out = ss.GetSHA256(); + return true; +} + template <class T> uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) { @@ -1329,7 +1582,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn uint256 hashPrevouts; uint256 hashSequence; uint256 hashOutputs; - const bool cacheready = cache && cache->m_ready; + const bool cacheready = cache && cache->m_bip143_segwit_ready; if (!(nHashType & SIGHASH_ANYONECANPAY)) { hashPrevouts = cacheready ? cache->hashPrevouts : SHA256Uint256(GetPrevoutsSHA256(txTo)); @@ -1389,13 +1642,19 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn } template <class T> -bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool GenericTransactionSignatureChecker<T>::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { return pubkey.Verify(sighash, vchSig); } template <class T> -bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool GenericTransactionSignatureChecker<T>::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const +{ + return pubkey.VerifySchnorr(sighash, sig); +} + +template <class T> +bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1410,13 +1669,41 @@ bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata); - if (!VerifySignature(vchSig, pubkey, sighash)) + if (!VerifyECDSASignature(vchSig, pubkey, sighash)) return false; return true; } template <class T> +bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror) const +{ + assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT); + // Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this. + assert(pubkey_in.size() == 32); + // Note that in Tapscript evaluation, empty signatures are treated specially (invalid signature that does not + // abort script execution). This is implemented in EvalChecksigTapscript, which won't invoke + // CheckSchnorrSignature in that case. In other contexts, they are invalid like every other signature with + // size different from 64 or 65. + if (sig.size() != 64 && sig.size() != 65) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_SIZE); + + XOnlyPubKey pubkey{pubkey_in}; + + uint8_t hashtype = SIGHASH_DEFAULT; + if (sig.size() == 65) { + hashtype = SpanPopBack(sig); + if (hashtype == SIGHASH_DEFAULT) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE); + } + uint256 sighash; + assert(this->txdata); + if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata)) { + return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE); + } + if (!VerifySchnorrSignature(sig, pubkey, sighash)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG); + return true; +} + +template <class T> bool GenericTransactionSignatureChecker<T>::CheckLockTime(const CScriptNum& nLockTime) const { // There are two kinds of nLockTime: lock-by-blockheight @@ -1504,17 +1791,39 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq template class GenericTransactionSignatureChecker<CTransaction>; template class GenericTransactionSignatureChecker<CMutableTransaction>; -static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptError* serror) +static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CScript& scriptPubKey, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror) { std::vector<valtype> stack{stack_span.begin(), stack_span.end()}; + if (sigversion == SigVersion::TAPSCRIPT) { + // OP_SUCCESSx processing overrides everything, including stack element size limits + CScript::const_iterator pc = scriptPubKey.begin(); + while (pc < scriptPubKey.end()) { + opcodetype opcode; + if (!scriptPubKey.GetOp(pc, opcode)) { + // Note how this condition would not be reached if an unknown OP_SUCCESSx was found + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + // New opcodes will be listed here. May use a different sigversion to modify existing opcodes. + if (IsOpSuccess(opcode)) { + if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS); + } + return set_success(serror); + } + } + + // Tapscript enforces initial stack size limits (altstack is empty here) + if (stack.size() > MAX_STACK_SIZE) return set_error(serror, SCRIPT_ERR_STACK_SIZE); + } + // Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack for (const valtype& elem : stack) { if (elem.size() > MAX_SCRIPT_ELEMENT_SIZE) return set_error(serror, SCRIPT_ERR_PUSH_SIZE); } // Run the script interpreter. - if (!EvalScript(stack, scriptPubKey, flags, checker, sigversion, serror)) return false; + if (!EvalScript(stack, scriptPubKey, flags, checker, sigversion, execdata, serror)) return false; // Scripts inside witness implicitly require cleanstack behaviour if (stack.size() != 1) return set_error(serror, SCRIPT_ERR_CLEANSTACK); @@ -1522,40 +1831,110 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS return true; } -static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) +static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, const std::vector<unsigned char>& program, const CScript& script, uint256& tapleaf_hash) { - CScript scriptPubKey; + const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE; + //! The inner pubkey (x-only, so no Y coordinate parity). + const XOnlyPubKey p{uint256(std::vector<unsigned char>(control.begin() + 1, control.begin() + TAPROOT_CONTROL_BASE_SIZE))}; + //! The output pubkey (taken from the scriptPubKey). + const XOnlyPubKey q{uint256(program)}; + // Compute the tapleaf hash. + tapleaf_hash = (CHashWriter(HASHER_TAPLEAF) << uint8_t(control[0] & TAPROOT_LEAF_MASK) << script).GetSHA256(); + // Compute the Merkle root from the leaf and the provided path. + uint256 k = tapleaf_hash; + for (int i = 0; i < path_len; ++i) { + CHashWriter ss_branch{HASHER_TAPBRANCH}; + Span<const unsigned char> node(control.data() + TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE); + if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) { + ss_branch << k << node; + } else { + ss_branch << node << k; + } + k = ss_branch.GetSHA256(); + } + // Compute the tweak from the Merkle root and the inner pubkey. + k = (CHashWriter(HASHER_TAPTWEAK) << MakeSpan(p) << k).GetSHA256(); + // Verify that the output pubkey matches the tweaked inner pubkey, after correcting for parity. + return q.CheckPayToContract(p, k, control[0] & 1); +} + +static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh) +{ + CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR) Span<const valtype> stack{witness.stack}; + ScriptExecutionData execdata; if (witversion == 0) { if (program.size() == WITNESS_V0_SCRIPTHASH_SIZE) { - // Version 0 segregated witness program: SHA256(CScript) inside the program, CScript + inputs in witness + // BIP141 P2WSH: 32-byte witness v0 program (which encodes SHA256(script)) if (stack.size() == 0) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY); } const valtype& script_bytes = SpanPopBack(stack); - scriptPubKey = CScript(script_bytes.begin(), script_bytes.end()); - uint256 hashScriptPubKey; - CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin()); - if (memcmp(hashScriptPubKey.begin(), program.data(), 32)) { + exec_script = CScript(script_bytes.begin(), script_bytes.end()); + uint256 hash_exec_script; + CSHA256().Write(&exec_script[0], exec_script.size()).Finalize(hash_exec_script.begin()); + if (memcmp(hash_exec_script.begin(), program.data(), 32)) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); } - return ExecuteWitnessScript(stack, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror); + return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::WITNESS_V0, checker, execdata, serror); } else if (program.size() == WITNESS_V0_KEYHASH_SIZE) { - // Special case for pay-to-pubkeyhash; signature + pubkey in witness + // BIP141 P2WPKH: 20-byte witness v0 program (which encodes Hash160(pubkey)) if (stack.size() != 2) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness } - scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG; - return ExecuteWitnessScript(stack, scriptPubKey, flags, SigVersion::WITNESS_V0, checker, serror); + exec_script << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG; + return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::WITNESS_V0, checker, execdata, serror); } else { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH); } + } else if (witversion == 1 && program.size() == WITNESS_V1_TAPROOT_SIZE && !is_p2sh) { + // BIP341 Taproot: 32-byte non-P2SH witness v1 program (which encodes a P2C-tweaked pubkey) + if (!(flags & SCRIPT_VERIFY_TAPROOT)) return set_success(serror); + if (stack.size() == 0) return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY); + if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) { + // Drop annex (this is non-standard; see IsWitnessStandard) + const valtype& annex = SpanPopBack(stack); + execdata.m_annex_hash = (CHashWriter(SER_GETHASH, 0) << annex).GetSHA256(); + execdata.m_annex_present = true; + } else { + execdata.m_annex_present = false; + } + execdata.m_annex_init = true; + if (stack.size() == 1) { + // Key path spending (stack size is 1 after removing optional annex) + if (!checker.CheckSchnorrSignature(stack.front(), program, SigVersion::TAPROOT, execdata, serror)) { + return false; // serror is set + } + return set_success(serror); + } else { + // Script path spending (stack size is >1 after removing optional annex) + const valtype& control = SpanPopBack(stack); + const valtype& script_bytes = SpanPopBack(stack); + exec_script = CScript(script_bytes.begin(), script_bytes.end()); + if (control.size() < TAPROOT_CONTROL_BASE_SIZE || control.size() > TAPROOT_CONTROL_MAX_SIZE || ((control.size() - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) { + return set_error(serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE); + } + if (!VerifyTaprootCommitment(control, program, exec_script, execdata.m_tapleaf_hash)) { + return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); + } + execdata.m_tapleaf_hash_init = true; + if ((control[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) { + // Tapscript (leaf version 0xc0) + execdata.m_validation_weight_left = ::GetSerializeSize(witness.stack, PROTOCOL_VERSION) + VALIDATION_WEIGHT_OFFSET; + execdata.m_validation_weight_left_init = true; + return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT, checker, execdata, serror); + } + if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION); + } + return set_success(serror); + } } else { if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); } - // Higher version witness scripts return true for future softfork compatibility + // Other version/size/p2sh combinations return true for future softfork compatibility return true; } // There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above. @@ -1601,7 +1980,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C // The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability. return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED); } - if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) { + if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror, /* is_p2sh */ false)) { return false; } // Bypass the cleanstack check at the end. The actual stack is obviously not clean @@ -1646,7 +2025,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C // reintroduce malleability. return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED_P2SH); } - if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) { + if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror, /* is_p2sh */ true)) { return false; } // Bypass the cleanstack check at the end. The actual stack is obviously not clean diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 71f2436369..b4c163c841 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,14 +7,17 @@ #define BITCOIN_SCRIPT_INTERPRETER_H #include <script/script_error.h> +#include <span.h> #include <primitives/transaction.h> #include <vector> #include <stdint.h> class CPubKey; +class XOnlyPubKey; class CScript; class CTransaction; +class CTxOut; class uint256; /** Signature hash types/flags */ @@ -24,6 +27,10 @@ enum SIGHASH_NONE = 2, SIGHASH_SINGLE = 3, SIGHASH_ANYONECANPAY = 0x80, + + SIGHASH_DEFAULT = 0, //!< Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL + SIGHASH_OUTPUT_MASK = 3, + SIGHASH_INPUT_MASK = 0x80, }; /** Script verification flags. @@ -79,6 +86,8 @@ enum // "Exactly one stack element must remain, and when interpreted as a boolean, it must be true". // (BIP62 rule 6) // Note: CLEANSTACK should never be used without P2SH or WITNESS. + // Note: WITNESS_V0 and TAPSCRIPT script execution have behavior similar to CLEANSTACK as part of their + // consensus rules. It is automatic there and does not need this flag. SCRIPT_VERIFY_CLEANSTACK = (1U << 8), // Verify CHECKLOCKTIMEVERIFY @@ -101,6 +110,8 @@ enum // Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector // + // Note: TAPSCRIPT script execution has behavior similar to MINIMALIF as part of its consensus + // rules. It is automatic there and does not depend on this flag. SCRIPT_VERIFY_MINIMALIF = (1U << 13), // Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed @@ -114,19 +125,49 @@ enum // Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts // SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16), + + // Taproot/Tapscript validation (BIPs 341 & 342) + // + SCRIPT_VERIFY_TAPROOT = (1U << 17), + + // Making unknown Taproot leaf versions non-standard + // + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1U << 18), + + // Making unknown OP_SUCCESS non-standard + SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1U << 19), + + // Making unknown public key versions (in BIP 342 scripts) non-standard + SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20), }; bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror); struct PrecomputedTransactionData { + // BIP341 precomputed data. + // These are single-SHA256, see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-15. + uint256 m_prevouts_single_hash; + uint256 m_sequences_single_hash; + uint256 m_outputs_single_hash; + uint256 m_spent_amounts_single_hash; + uint256 m_spent_scripts_single_hash; + //! Whether the 5 fields above are initialized. + bool m_bip341_taproot_ready = false; + + // BIP143 precomputed data (double-SHA256). uint256 hashPrevouts, hashSequence, hashOutputs; - bool m_ready = false; + //! Whether the 3 fields above are initialized. + bool m_bip143_segwit_ready = false; + + std::vector<CTxOut> m_spent_outputs; + //! Whether m_spent_outputs is initialized. + bool m_spent_outputs_ready = false; PrecomputedTransactionData() = default; template <class T> - void Init(const T& tx); + void Init(const T& tx, std::vector<CTxOut>&& spent_outputs); template <class T> explicit PrecomputedTransactionData(const T& tx); @@ -134,13 +175,48 @@ struct PrecomputedTransactionData enum class SigVersion { - BASE = 0, - WITNESS_V0 = 1, + BASE = 0, //!< Bare scripts and BIP16 P2SH-wrapped redeemscripts + WITNESS_V0 = 1, //!< Witness v0 (P2WPKH and P2WSH); see BIP 141 + TAPROOT = 2, //!< Witness v1 with 32-byte program, not BIP16 P2SH-wrapped, key path spending; see BIP 341 + TAPSCRIPT = 3, //!< Witness v1 with 32-byte program, not BIP16 P2SH-wrapped, script path spending, leaf version 0xc0; see BIP 342 +}; + +struct ScriptExecutionData +{ + //! Whether m_tapleaf_hash is initialized. + bool m_tapleaf_hash_init = false; + //! The tapleaf hash. + uint256 m_tapleaf_hash; + + //! Whether m_codeseparator_pos is initialized. + bool m_codeseparator_pos_init = false; + //! Opcode position of the last executed OP_CODESEPARATOR (or 0xFFFFFFFF if none executed). + uint32_t m_codeseparator_pos; + + //! Whether m_annex_present and (when needed) m_annex_hash are initialized. + bool m_annex_init = false; + //! Whether an annex is present. + bool m_annex_present; + //! Hash of the annex data. + uint256 m_annex_hash; + + //! Whether m_validation_weight_left is initialized. + bool m_validation_weight_left_init = false; + //! How much validation weight is left (decremented for every successful non-empty signature check). + int64_t m_validation_weight_left; }; /** Signature hash sizes */ static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32; static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20; +static constexpr size_t WITNESS_V1_TAPROOT_SIZE = 32; + +static constexpr uint8_t TAPROOT_LEAF_MASK = 0xfe; +static constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT = 0xc0; +static constexpr size_t TAPROOT_CONTROL_BASE_SIZE = 33; +static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32; +static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128; +static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT; template <class T> uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); @@ -148,7 +224,12 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn class BaseSignatureChecker { public: - virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + virtual bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + { + return false; + } + + virtual bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const { return false; } @@ -176,12 +257,14 @@ private: const PrecomputedTransactionData* txdata; protected: - virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; + virtual bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; + virtual bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const; public: GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {} GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} - bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; + bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; + bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; }; @@ -189,6 +272,7 @@ public: using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>; using MutableTransactionSignatureChecker = GenericTransactionSignatureChecker<CMutableTransaction>; +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr); bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr); diff --git a/src/script/keyorigin.h b/src/script/keyorigin.h index a318ff0f9d..210395d177 100644 --- a/src/script/keyorigin.h +++ b/src/script/keyorigin.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/script.cpp b/src/script/script.cpp index 92c6fe7785..9a6419088b 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -140,6 +140,9 @@ std::string GetOpName(opcodetype opcode) case OP_NOP9 : return "OP_NOP9"; case OP_NOP10 : return "OP_NOP10"; + // Opcode added by BIP 342 (Tapscript) + case OP_CHECKSIGADD : return "OP_CHECKSIGADD"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; default: @@ -328,3 +331,11 @@ bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator en opcodeRet = static_cast<opcodetype>(opcode); return true; } + +bool IsOpSuccess(const opcodetype& opcode) +{ + return opcode == 80 || opcode == 98 || (opcode >= 126 && opcode <= 129) || + (opcode >= 131 && opcode <= 134) || (opcode >= 137 && opcode <= 138) || + (opcode >= 141 && opcode <= 142) || (opcode >= 149 && opcode <= 153) || + (opcode >= 187 && opcode <= 254); +} diff --git a/src/script/script.h b/src/script/script.h index c1f2b66921..974cde4984 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -44,6 +44,17 @@ static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 // SEQUENCE_FINAL). static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU; +// Tag for input annex. If there are at least two witness elements for a transaction input, +// and the first byte of the last element is 0x50, this last element is called annex, and +// has meanings independent of the script +static constexpr unsigned int ANNEX_TAG = 0x50; + +// Validation weight per passing signature (Tapscript only, see BIP 342). +static constexpr uint64_t VALIDATION_WEIGHT_PER_SIGOP_PASSED = 50; + +// How much weight budget is added to the witness size (Tapscript only, see BIP 342). +static constexpr uint64_t VALIDATION_WEIGHT_OFFSET = 50; + template <typename T> std::vector<unsigned char> ToByteVector(const T& in) { @@ -187,6 +198,9 @@ enum opcodetype OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, + // Opcode added by BIP 342 (Tapscript) + OP_CHECKSIGADD = 0xba, + OP_INVALIDOPCODE = 0xff, }; @@ -555,4 +569,7 @@ struct CScriptWitness std::string ToString() const; }; +/** Test for OP_SUCCESSx opcodes as defined by BIP342. */ +bool IsOpSuccess(const opcodetype& opcode); + #endif // BITCOIN_SCRIPT_SCRIPT_H diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 69e14803f1..fadc04262c 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -73,10 +73,16 @@ std::string ScriptErrorString(const ScriptError serror) return "NOPx reserved for soft-fork upgrades"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: return "Witness version reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION: + return "Taproot version reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_OP_SUCCESS: + return "OP_SUCCESSx reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE: + return "Public key version reserved for soft-fork upgrades"; case SCRIPT_ERR_PUBKEYTYPE: return "Public key is neither compressed or uncompressed"; case SCRIPT_ERR_CLEANSTACK: - return "Extra items left on stack after execution"; + return "Stack size must be exactly one after execution"; case SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH: return "Witness program has incorrect length"; case SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY: @@ -91,6 +97,20 @@ std::string ScriptErrorString(const ScriptError serror) return "Witness provided for non-witness script"; case SCRIPT_ERR_WITNESS_PUBKEYTYPE: return "Using non-compressed keys in segwit"; + case SCRIPT_ERR_SCHNORR_SIG_SIZE: + return "Invalid Schnorr signature size"; + case SCRIPT_ERR_SCHNORR_SIG_HASHTYPE: + return "Invalid Schnorr signature hash type"; + case SCRIPT_ERR_SCHNORR_SIG: + return "Invalid Schnorr signature"; + case SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE: + return "Invalid Taproot control block size"; + case SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT: + return "Too much signature validation relative to witness weight"; + case SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG: + return "OP_CHECKMULTISIG(VERIFY) is not available in tapscript"; + case SCRIPT_ERR_TAPSCRIPT_MINIMALIF: + return "OP_IF/NOTIF argument must be minimal in tapscript"; case SCRIPT_ERR_OP_CODESEPARATOR: return "Using OP_CODESEPARATOR in non-witness script"; case SCRIPT_ERR_SIG_FINDANDDELETE: diff --git a/src/script/script_error.h b/src/script/script_error.h index 2978c147e1..44e68fe0fa 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -56,6 +56,9 @@ typedef enum ScriptError_t /* softfork safeness */ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, + SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION, + SCRIPT_ERR_DISCOURAGE_OP_SUCCESS, + SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE, /* segregated witness */ SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH, @@ -66,6 +69,15 @@ typedef enum ScriptError_t SCRIPT_ERR_WITNESS_UNEXPECTED, SCRIPT_ERR_WITNESS_PUBKEYTYPE, + /* Taproot */ + SCRIPT_ERR_SCHNORR_SIG_SIZE, + SCRIPT_ERR_SCHNORR_SIG_HASHTYPE, + SCRIPT_ERR_SCHNORR_SIG, + SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE, + SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT, + SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG, + SCRIPT_ERR_TAPSCRIPT_MINIMALIF, + /* Constant scriptCode */ SCRIPT_ERR_OP_CODESEPARATOR, SCRIPT_ERR_SIG_FINDANDDELETE, diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index aaecab1ef2..2bfe206597 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -22,8 +22,9 @@ namespace { class CSignatureCache { private: - //! Entries are SHA256(nonce || signature hash || public key || signature): - CSHA256 m_salted_hasher; + //! Entries are SHA256(nonce || 'E' or 'S' || 31 zero bytes || signature hash || public key || signature): + CSHA256 m_salted_hasher_ecdsa; + CSHA256 m_salted_hasher_schnorr; typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; map_type setValid; boost::shared_mutex cs_sigcache; @@ -34,18 +35,30 @@ public: uint256 nonce = GetRandHash(); // We want the nonce to be 64 bytes long to force the hasher to process // this chunk, which makes later hash computations more efficient. We - // just write our 32-byte entropy twice to fill the 64 bytes. - m_salted_hasher.Write(nonce.begin(), 32); - m_salted_hasher.Write(nonce.begin(), 32); + // just write our 32-byte entropy, and then pad with 'E' for ECDSA and + // 'S' for Schnorr (followed by 0 bytes). + static constexpr unsigned char PADDING_ECDSA[32] = {'E'}; + static constexpr unsigned char PADDING_SCHNORR[32] = {'S'}; + m_salted_hasher_ecdsa.Write(nonce.begin(), 32); + m_salted_hasher_ecdsa.Write(PADDING_ECDSA, 32); + m_salted_hasher_schnorr.Write(nonce.begin(), 32); + m_salted_hasher_schnorr.Write(PADDING_SCHNORR, 32); } void - ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) + ComputeEntryECDSA(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) const { - CSHA256 hasher = m_salted_hasher; + CSHA256 hasher = m_salted_hasher_ecdsa; hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin()); } + void + ComputeEntrySchnorr(uint256& entry, const uint256 &hash, Span<const unsigned char> sig, const XOnlyPubKey& pubkey) const + { + CSHA256 hasher = m_salted_hasher_schnorr; + hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(sig.data(), sig.size()).Finalize(entry.begin()); + } + bool Get(const uint256& entry, const bool erase) { @@ -53,7 +66,7 @@ public: return setValid.contains(entry, erase); } - void Set(uint256& entry) + void Set(const uint256& entry) { boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); setValid.insert(entry); @@ -85,15 +98,25 @@ void InitSignatureCache() (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems); } -bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { uint256 entry; - signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); + signatureCache.ComputeEntryECDSA(entry, sighash, vchSig, pubkey); if (signatureCache.Get(entry, !store)) return true; - if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) + if (!TransactionSignatureChecker::VerifyECDSASignature(vchSig, pubkey, sighash)) return false; if (store) signatureCache.Set(entry); return true; } + +bool CachingTransactionSignatureChecker::VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const +{ + uint256 entry; + signatureCache.ComputeEntrySchnorr(entry, sighash, sig, pubkey); + if (signatureCache.Get(entry, !store)) return true; + if (!TransactionSignatureChecker::VerifySchnorrSignature(sig, pubkey, sighash)) return false; + if (store) signatureCache.Set(entry); + return true; +} diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 807b61b542..bf0ba38c2d 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,8 @@ #define BITCOIN_SCRIPT_SIGCACHE_H #include <script/interpreter.h> +#include <span.h> +#include <util/hasher.h> #include <vector> @@ -19,27 +21,6 @@ static const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384; class CPubKey; -/** - * We're hashing a nonce into the entries themselves, so we don't need extra - * blinding in the set hash computation. - * - * This may exhibit platform endian dependent behavior but because these are - * nonced hashes (random) and this state is only ever used locally it is safe. - * All that matters is local consistency. - */ -class SignatureCacheHasher -{ -public: - template <uint8_t hash_select> - uint32_t operator()(const uint256& key) const - { - static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available."); - uint32_t u; - std::memcpy(&u, key.begin()+4*hash_select, 4); - return u; - } -}; - class CachingTransactionSignatureChecker : public TransactionSignatureChecker { private: @@ -48,7 +29,8 @@ private: public: CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn), store(storeIn) {} - bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override; + bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override; + bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override; }; void InitSignatureCache(); diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 9b3f94f14d..8afbe9ebed 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -111,6 +111,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TxoutType::NONSTANDARD: case TxoutType::NULL_DATA: case TxoutType::WITNESS_UNKNOWN: + case TxoutType::WITNESS_V1_TAPROOT: return false; case TxoutType::PUBKEY: if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false; @@ -260,9 +261,9 @@ private: public: SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {} - bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override + bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { - if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) { + if (checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) { CPubKey pubkey(vchPubKey); sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig)); return true; @@ -339,7 +340,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI for (unsigned int i = last_success_key; i < num_pubkeys; ++i) { const valtype& pubkey = solutions[i+1]; // We either have a signature for this pubkey, or we have found a signature and it is valid - if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, next_script, sigversion)) { + if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckECDSASignature(sig, pubkey, next_script, sigversion)) { last_success_key = i + 1; break; } @@ -387,7 +388,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) { assert(nIn < txTo.vin.size()); - CTxIn& txin = txTo.vin[nIn]; + const CTxIn& txin = txTo.vin[nIn]; assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; @@ -400,7 +401,7 @@ class DummySignatureChecker final : public BaseSignatureChecker { public: DummySignatureChecker() {} - bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; } + bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; } }; const DummySignatureChecker DUMMY_CHECKER; diff --git a/src/script/sign.h b/src/script/sign.h index b77d26c0d7..a1cfe1574d 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -11,6 +11,7 @@ #include <pubkey.h> #include <script/interpreter.h> #include <script/keyorigin.h> +#include <span.h> #include <streams.h> class CKey; diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index 2d8dc7d471..9781ec32af 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -179,18 +179,18 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& { // Only supports destinations which map to single public keys, i.e. P2PKH, // P2WPKH, and P2SH-P2WPKH. - if (auto id = boost::get<PKHash>(&dest)) { + if (auto id = std::get_if<PKHash>(&dest)) { return ToKeyID(*id); } - if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) { + if (auto witness_id = std::get_if<WitnessV0KeyHash>(&dest)) { return ToKeyID(*witness_id); } - if (auto script_hash = boost::get<ScriptHash>(&dest)) { + if (auto script_hash = std::get_if<ScriptHash>(&dest)) { CScript script; CScriptID script_id(*script_hash); CTxDestination inner_dest; if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) { - if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) { + if (auto inner_witness_id = std::get_if<WitnessV0KeyHash>(&inner_dest)) { return ToKeyID(*inner_witness_id); } } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 96a3d311a6..7967c01858 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -55,6 +55,7 @@ std::string GetTxnOutputType(TxoutType t) case TxoutType::NULL_DATA: return "nulldata"; case TxoutType::WITNESS_V0_KEYHASH: return "witness_v0_keyhash"; case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash"; + case TxoutType::WITNESS_V1_TAPROOT: return "witness_v1_taproot"; case TxoutType::WITNESS_UNKNOWN: return "witness_unknown"; } // no default case, so the compiler can warn about missing cases assert(false); @@ -130,6 +131,11 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned c vSolutionsRet.push_back(witnessprogram); return TxoutType::WITNESS_V0_SCRIPTHASH; } + if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE) { + vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); + vSolutionsRet.push_back(std::move(witnessprogram)); + return TxoutType::WITNESS_V1_TAPROOT; + } if (witnessversion != 0) { vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion}); vSolutionsRet.push_back(std::move(witnessprogram)); @@ -203,7 +209,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin()); addressRet = hash; return true; - } else if (whichType == TxoutType::WITNESS_UNKNOWN) { + } else if (whichType == TxoutType::WITNESS_UNKNOWN || whichType == TxoutType::WITNESS_V1_TAPROOT) { WitnessUnknown unk; unk.version = vSolutions[0][0]; std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program); @@ -255,9 +261,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::v return true; } -namespace -{ -class CScriptVisitor : public boost::static_visitor<CScript> +namespace { +class CScriptVisitor { public: CScript operator()(const CNoDestination& dest) const @@ -294,7 +299,7 @@ public: CScript GetScriptForDestination(const CTxDestination& dest) { - return boost::apply_visitor(CScriptVisitor(), dest); + return std::visit(CScriptVisitor(), dest); } CScript GetScriptForRawPubKey(const CPubKey& pubKey) @@ -314,5 +319,5 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys) } bool IsValidDestination(const CTxDestination& dest) { - return dest.which() != 0; + return dest.index() != 0; } diff --git a/src/script/standard.h b/src/script/standard.h index 6dbcd04968..d5d87392ad 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -9,10 +9,8 @@ #include <script/interpreter.h> #include <uint256.h> -#include <boost/variant.hpp> - #include <string> - +#include <variant> static const bool DEFAULT_ACCEPT_DATACARRIER = true; @@ -28,7 +26,7 @@ protected: public: BaseHash() : m_hash() {} - BaseHash(const HashType& in) : m_hash(in) {} + explicit BaseHash(const HashType& in) : m_hash(in) {} unsigned char* begin() { @@ -129,6 +127,7 @@ enum class TxoutType { NULL_DATA, //!< unspendable OP_RETURN script that carries data WITNESS_V0_SCRIPTHASH, WITNESS_V0_KEYHASH, + WITNESS_V1_TAPROOT, WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above }; @@ -206,10 +205,11 @@ struct WitnessUnknown * * ScriptHash: TxoutType::SCRIPTHASH destination (P2SH) * * WitnessV0ScriptHash: TxoutType::WITNESS_V0_SCRIPTHASH destination (P2WSH) * * WitnessV0KeyHash: TxoutType::WITNESS_V0_KEYHASH destination (P2WPKH) - * * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W???) + * * WitnessUnknown: TxoutType::WITNESS_UNKNOWN/WITNESS_V1_TAPROOT destination (P2W???) + * (taproot outputs do not require their own type as long as no wallet support exists) * A CTxDestination is the internal data type encoded in a bitcoin address */ -typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination; +using CTxDestination = std::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown>; /** Check whether a CTxDestination is a CNoDestination. */ bool IsValidDestination(const CTxDestination& dest); diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml index e1a88c4051..ce8d6391b2 100644 --- a/src/secp256k1/.travis.yml +++ b/src/secp256k1/.travis.yml @@ -17,33 +17,29 @@ compiler: - gcc env: global: - - WIDEMUL=auto BIGNUM=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no SCHNORRSIG=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2 + - WIDEMUL=auto BIGNUM=auto STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check WITH_VALGRIND=yes RUN_VALGRIND=no EXTRAFLAGS= HOST= ECDH=no RECOVERY=no SCHNORRSIG=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2 matrix: - WIDEMUL=int64 RECOVERY=yes - WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - - WIDEMUL=int64 ENDOMORPHISM=yes - WIDEMUL=int128 - WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - - WIDEMUL=int128 ENDOMORPHISM=yes - - WIDEMUL=int128 ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes + - WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes - WIDEMUL=int128 ASM=x86_64 - - WIDEMUL=int128 ENDOMORPHISM=yes ASM=x86_64 - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes + - BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes - BIGNUM=no STATICPRECOMPUTATION=no - - BUILD=distcheck CTIMETEST= BENCH= + - BUILD=distcheck WITH_VALGRIND=no CTIMETEST=no BENCH=no - CPPFLAGS=-DDETERMINISTIC - - CFLAGS=-O0 CTIMETEST= + - CFLAGS=-O0 CTIMETEST=no - ECMULTGENPRECISION=2 - ECMULTGENPRECISION=8 - - VALGRIND=yes ENDOMORPHISM=yes BIGNUM=no ASM=x86_64 EXPERIMENTAL=yes ECDH=yes RECOVERY=yes EXTRAFLAGS="--disable-openssl-tests" CPPFLAGS=-DVALGRIND BUILD= - - VALGRIND=yes BIGNUM=no ASM=x86_64 EXPERIMENTAL=yes ECDH=yes RECOVERY=yes EXTRAFLAGS="--disable-openssl-tests" CPPFLAGS=-DVALGRIND BUILD= + - RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD= matrix: fast_finish: true include: - compiler: clang os: linux - env: HOST=i686-linux-gnu ENDOMORPHISM=yes + env: HOST=i686-linux-gnu addons: apt: packages: @@ -63,7 +59,7 @@ matrix: - libtool-bin - libc6-dbg:i386 - compiler: gcc - env: HOST=i686-linux-gnu ENDOMORPHISM=yes + env: HOST=i686-linux-gnu os: linux addons: apt: @@ -85,7 +81,7 @@ matrix: - libc6-dbg:i386 # S390x build (big endian system) - compiler: gcc - env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes CTIMETEST= + env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes CTIMETEST= arch: s390x # We use this to install macOS dependencies instead of the built in `homebrew` plugin, diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md index 434178b372..e070937235 100644 --- a/src/secp256k1/README.md +++ b/src/secp256k1/README.md @@ -16,7 +16,7 @@ Features: * Very efficient implementation. * Suitable for embedded systems. * Optional module for public key recovery. -* Optional module for ECDH key exchange (experimental). +* Optional module for ECDH key exchange. Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable. @@ -48,7 +48,7 @@ Implementation details * Use wNAF notation for point multiplicands. * Use a much larger window for multiples of G, using precomputed multiples. * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. - * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. + * Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. * Point multiplication for signing * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. * Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains) diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 index 57595f4499..ece3d655ed 100644 --- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -36,16 +36,39 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then CPPFLAGS_TEMP="$CPPFLAGS" CPPFLAGS="$CRYPTO_CPPFLAGS $CPPFLAGS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include <openssl/bn.h> #include <openssl/ec.h> #include <openssl/ecdsa.h> #include <openssl/obj_mac.h>]],[[ - EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); - ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); + # if OPENSSL_VERSION_NUMBER < 0x10100000L + void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {(void)sig->r; (void)sig->s;} + # endif + + unsigned int zero = 0; + const unsigned char *zero_ptr = (unsigned char*)&zero; + EC_KEY_free(EC_KEY_new_by_curve_name(NID_secp256k1)); + EC_KEY *eckey = EC_KEY_new(); + EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp256k1); + EC_KEY_set_group(eckey, group); + ECDSA_sign(0, NULL, 0, NULL, &zero, eckey); ECDSA_verify(0, NULL, 0, NULL, 0, eckey); + o2i_ECPublicKey(&eckey, &zero_ptr, 0); + d2i_ECPrivateKey(&eckey, &zero_ptr, 0); + EC_KEY_check_key(eckey); EC_KEY_free(eckey); + EC_GROUP_free(group); ECDSA_SIG *sig_openssl; sig_openssl = ECDSA_SIG_new(); + d2i_ECDSA_SIG(&sig_openssl, &zero_ptr, 0); + i2d_ECDSA_SIG(sig_openssl, NULL); + ECDSA_SIG_get0(sig_openssl, NULL, NULL); ECDSA_SIG_free(sig_openssl); + const BIGNUM *bignum = BN_value_one(); + BN_is_negative(bignum); + BN_num_bits(bignum); + if (sizeof(zero) >= BN_num_bytes(bignum)) { + BN_bn2bin(bignum, (unsigned char*)&zero); + } ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) AC_MSG_RESULT([$has_openssl_ec]) CPPFLAGS="$CPPFLAGS_TEMP" diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac index 6fe8984f4d..eb3b449bec 100644 --- a/src/secp256k1/configure.ac +++ b/src/secp256k1/configure.ac @@ -67,7 +67,7 @@ esac CFLAGS="-W $CFLAGS" -warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings" +warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef -Wno-unused-function -Wno-long-long -Wno-overlength-strings" saved_CFLAGS="$CFLAGS" CFLAGS="$warn_CFLAGS $CFLAGS" AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) @@ -116,18 +116,13 @@ AC_ARG_ENABLE(exhaustive_tests, [use_exhaustive_tests=$enableval], [use_exhaustive_tests=yes]) -AC_ARG_ENABLE(endomorphism, - AS_HELP_STRING([--enable-endomorphism],[enable endomorphism [default=no]]), - [use_endomorphism=$enableval], - [use_endomorphism=no]) - AC_ARG_ENABLE(ecmult_static_precomputation, AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing [default=auto]]), [use_ecmult_static_precomputation=$enableval], [use_ecmult_static_precomputation=auto]) AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation]), [enable_module_ecdh=$enableval], [enable_module_ecdh=no]) @@ -164,8 +159,7 @@ AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto], AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], [window size for ecmult precomputation for verification, specified as integer in range [2..24].] [Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.] -[The table will store 2^(SIZE-2) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] -[If the endomorphism optimization is enabled, two tables of this size are used instead of only one.] +[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.] ["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]] )], [req_ecmult_window=$withval], [req_ecmult_window=auto]) @@ -178,7 +172,21 @@ AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision )], [req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto]) -AC_CHECK_HEADER([valgrind/memcheck.h], [enable_valgrind=yes], [enable_valgrind=no], []) +AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto], +[Build with extra checks for running inside Valgrind [default=auto]] +)], +[req_valgrind=$withval], [req_valgrind=auto]) + +if test x"$req_valgrind" = x"no"; then + enable_valgrind=no +else + AC_CHECK_HEADER([valgrind/memcheck.h], [enable_valgrind=yes], [ + if test x"$req_valgrind" = x"yes"; then + AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available]) + fi + enable_valgrind=no + ], []) +fi AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"]) if test x"$enable_coverage" = x"yes"; then @@ -387,8 +395,8 @@ esac if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK - if test x"$has_openssl_ec" = x"yes"; then - if test x"$enable_openssl_tests" != x"no"; then + if test x"$enable_openssl_tests" != x"no" && test x"$has_openssl_ec" = x"yes"; then + enable_openssl_tests=yes AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS $CRYPTO_CPPFLAGS" SECP_TEST_LIBS="$CRYPTO_LIBS" @@ -398,16 +406,17 @@ if test x"$use_tests" = x"yes"; then SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" ;; esac - fi else if test x"$enable_openssl_tests" = x"yes"; then AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) fi + enable_openssl_tests=no fi else if test x"$enable_openssl_tests" = x"yes"; then AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) fi + enable_openssl_tests=no fi if test x"$set_bignum" = x"gmp"; then @@ -415,10 +424,6 @@ if test x"$set_bignum" = x"gmp"; then SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" fi -if test x"$use_endomorphism" = x"yes"; then - AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) -fi - if test x"$set_precomp" = x"yes"; then AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) fi @@ -454,14 +459,10 @@ if test x"$enable_experimental" = x"yes"; then AC_MSG_NOTICE([******]) AC_MSG_NOTICE([WARNING: experimental build]) AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) - AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys]) AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig]) AC_MSG_NOTICE([******]) else - if test x"$enable_module_ecdh" = x"yes"; then - AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) - fi if test x"$enable_module_extrakeys" = x"yes"; then AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.]) fi @@ -500,10 +501,11 @@ AC_OUTPUT echo echo "Build Options:" -echo " with endomorphism = $use_endomorphism" echo " with ecmult precomp = $set_precomp" echo " with external callbacks = $use_external_default_callbacks" echo " with benchmarks = $use_benchmark" +echo " with tests = $use_tests" +echo " with openssl tests = $enable_openssl_tests" echo " with coverage = $enable_coverage" echo " module ecdh = $enable_module_ecdh" echo " module recovery = $enable_module_recovery" diff --git a/src/secp256k1/contrib/travis.sh b/src/secp256k1/contrib/travis.sh index b0b55b44b8..24cc9315cb 100755 --- a/src/secp256k1/contrib/travis.sh +++ b/src/secp256k1/contrib/travis.sh @@ -13,27 +13,28 @@ then fi ./configure \ - --enable-experimental="$EXPERIMENTAL" --enable-endomorphism="$ENDOMORPHISM" \ + --enable-experimental="$EXPERIMENTAL" \ --with-test-override-wide-multiply="$WIDEMUL" --with-bignum="$BIGNUM" --with-asm="$ASM" \ --enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \ --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-schnorrsig="$SCHNORRSIG" \ + --with-valgrind="$WITH_VALGRIND" \ --host="$HOST" $EXTRAFLAGS if [ -n "$BUILD" ] then make -j2 "$BUILD" fi -if [ -n "$VALGRIND" ] +if [ "$RUN_VALGRIND" = "yes" ] then make -j2 # the `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (http://valgrind.org/docs/manual/manual-core.html) valgrind --error-exitcode=42 ./tests 16 valgrind --error-exitcode=42 ./exhaustive_tests fi -if [ -n "$BENCH" ] +if [ "$BENCH" = "yes" ] then - if [ -n "$VALGRIND" ] + if [ "$RUN_VALGRIND" = "yes" ] then # Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool EXEC='./libtool --mode=execute valgrind --error-exitcode=42' @@ -56,8 +57,12 @@ then then $EXEC ./bench_ecdh >> bench.log 2>&1 fi + if [ "$SCHNORRSIG" = "yes" ] + then + $EXEC ./bench_schnorrsig >> bench.log 2>&1 + fi fi -if [ -n "$CTIMETEST" ] +if [ "$CTIMETEST" = "yes" ] then ./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1 fi diff --git a/src/secp256k1/sage/gen_exhaustive_groups.sage b/src/secp256k1/sage/gen_exhaustive_groups.sage new file mode 100644 index 0000000000..3c3c984811 --- /dev/null +++ b/src/secp256k1/sage/gen_exhaustive_groups.sage @@ -0,0 +1,129 @@ +# Define field size and field +P = 2^256 - 2^32 - 977 +F = GF(P) +BETA = F(0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee) + +assert(BETA != F(1) and BETA^3 == F(1)) + +orders_done = set() +results = {} +first = True +for b in range(1, P): + # There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all. + if len(orders_done) == 6: + break + + E = EllipticCurve(F, [0, b]) + print("Analyzing curve y^2 = x^3 + %i" % b) + n = E.order() + # Skip curves with an order we've already tried + if n in orders_done: + print("- Isomorphic to earlier curve") + continue + orders_done.add(n) + # Skip curves isomorphic to the real secp256k1 + if n.is_pseudoprime(): + print(" - Isomorphic to secp256k1") + continue + + print("- Finding subgroups") + + # Find what prime subgroups exist + for f, _ in n.factor(): + print("- Analyzing subgroup of order %i" % f) + # Skip subgroups of order >1000 + if f < 4 or f > 1000: + print(" - Bad size") + continue + + # Iterate over X coordinates until we find one that is on the curve, has order f, + # and for which curve isomorphism exists that maps it to X coordinate 1. + for x in range(1, P): + # Skip X coordinates not on the curve, and construct the full point otherwise. + if not E.is_x_coord(x): + continue + G = E.lift_x(F(x)) + + print(" - Analyzing (multiples of) point with X=%i" % x) + + # Skip points whose order is not a multiple of f. Project the point to have + # order f otherwise. + if (G.order() % f): + print(" - Bad order") + continue + G = G * (G.order() // f) + + # Find lambda for endomorphism. Skip if none can be found. + lam = None + for l in Integers(f)(1).nth_root(3, all=True): + if int(l)*G == E(BETA*G[0], G[1]): + lam = int(l) + break + if lam is None: + print(" - No endomorphism for this subgroup") + break + + # Now look for an isomorphism of the curve that gives this point an X + # coordinate equal to 1. + # If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b. + # So look for m=a^2=1/x. + m = F(1)/G[0] + if not m.is_square(): + print(" - No curve isomorphism maps it to a point with X=1") + continue + a = m.sqrt() + rb = a^6*b + RE = EllipticCurve(F, [0, rb]) + + # Use as generator twice the image of G under the above isormorphism. + # This means that generator*(1/2 mod f) will have X coordinate 1. + RG = RE(1, a^3*G[1]) * 2 + # And even Y coordinate. + if int(RG[1]) % 2: + RG = -RG + assert(RG.order() == f) + assert(lam*RG == RE(BETA*RG[0], RG[1])) + + # We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it + results[f] = {"b": rb, "G": RG, "lambda": lam} + print(" - Found solution") + break + + print("") + +print("") +print("") +print("/* To be put in src/group_impl.h: */") +first = True +for f in sorted(results.keys()): + b = results[f]["b"] + G = results[f]["G"] + print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) + first = False + print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(") + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(");") + print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(") + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) + print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) + print(");") +print("# else") +print("# error No known generator for the specified exhaustive test group order.") +print("# endif") + +print("") +print("") +print("/* To be put in src/scalar_impl.h: */") +first = True +for f in sorted(results.keys()): + lam = results[f]["lambda"] + print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) + first = False + print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) +print("# else") +print("# error No known lambda for the specified exhaustive test group order.") +print("# endif") +print("") diff --git a/src/secp256k1/src/assumptions.h b/src/secp256k1/src/assumptions.h index f9d4e8e793..77204de2b8 100644 --- a/src/secp256k1/src/assumptions.h +++ b/src/secp256k1/src/assumptions.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_ASSUMPTIONS_H #define SECP256K1_ASSUMPTIONS_H +#include <limits.h> + #include "util.h" /* This library, like most software, relies on a number of compiler implementation defined (but not undefined) @@ -19,7 +21,11 @@ struct secp256k1_assumption_checker { allowed. */ int dummy_array[( /* Bytes are 8 bits. */ - CHAR_BIT == 8 && + (CHAR_BIT == 8) && + + /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 + without signed overflow, which would be undefined behaviour. */ + (UINT_MAX <= UINT32_MAX) && /* Conversions from unsigned to signed outside of the bounds of the signed type are implementation-defined. Verify that they function as reinterpreting the lower diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h index 83dbe6f25b..b0d82e89b4 100644 --- a/src/secp256k1/src/basic-config.h +++ b/src/secp256k1/src/basic-config.h @@ -11,7 +11,6 @@ #undef USE_ASM_X86_64 #undef USE_ECMULT_STATIC_PRECOMPUTATION -#undef USE_ENDOMORPHISM #undef USE_EXTERNAL_ASM #undef USE_EXTERNAL_DEFAULT_CALLBACKS #undef USE_FIELD_INV_BUILTIN diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c index 9687fe4482..5f2b7a9759 100644 --- a/src/secp256k1/src/bench_internal.c +++ b/src/secp256k1/src/bench_internal.c @@ -117,7 +117,6 @@ void bench_scalar_mul(void* arg, int iters) { } } -#ifdef USE_ENDOMORPHISM void bench_scalar_split(void* arg, int iters) { int i, j = 0; bench_inv *data = (bench_inv*)arg; @@ -128,7 +127,6 @@ void bench_scalar_split(void* arg, int iters) { } CHECK(j <= iters); } -#endif void bench_scalar_inverse(void* arg, int iters) { int i, j = 0; @@ -397,9 +395,7 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100); if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10); if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10); -#ifdef USE_ENDOMORPHISM if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters); -#endif if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000); if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000); diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h index c9b198239d..09e8146414 100644 --- a/src/secp256k1/src/ecmult.h +++ b/src/secp256k1/src/ecmult.h @@ -15,9 +15,7 @@ typedef struct { /* For accelerating the computation of a*P + b*G: */ secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ -#ifdef USE_ENDOMORPHISM secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ -#endif } secp256k1_ecmult_context; static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE; diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h index 55b61e4937..bb9511108b 100644 --- a/src/secp256k1/src/ecmult_const_impl.h +++ b/src/secp256k1/src/ecmult_const_impl.h @@ -140,19 +140,16 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons secp256k1_fe Z; int skew_1; -#ifdef USE_ENDOMORPHISM secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; int skew_lam; secp256k1_scalar q_1, q_lam; -#endif int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; int i; /* build wnaf representation for q. */ int rsize = size; -#ifdef USE_ENDOMORPHISM if (size > 128) { rsize = 128; /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ @@ -160,12 +157,9 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128); skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128); } else -#endif { skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size); -#ifdef USE_ENDOMORPHISM skew_lam = 0; -#endif } /* Calculate odd multiples of a. @@ -179,14 +173,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { secp256k1_fe_normalize_weak(&pre_a[i].y); } -#ifdef USE_ENDOMORPHISM if (size > 128) { for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); } } -#endif /* first loop iteration (separated out so we can directly set r, rather * than having it start at infinity, get doubled several times, then have @@ -195,14 +187,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons VERIFY_CHECK(i != 0); ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); secp256k1_gej_set_ge(r, &tmpa); -#ifdef USE_ENDOMORPHISM if (size > 128) { i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)]; VERIFY_CHECK(i != 0); ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); secp256k1_gej_add_ge(r, r, &tmpa); } -#endif /* remaining loop iterations */ for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) { int n; @@ -215,14 +205,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); VERIFY_CHECK(n != 0); secp256k1_gej_add_ge(r, r, &tmpa); -#ifdef USE_ENDOMORPHISM if (size > 128) { n = wnaf_lam[i]; ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); VERIFY_CHECK(n != 0); secp256k1_gej_add_ge(r, r, &tmpa); } -#endif } secp256k1_fe_mul(&r->z, &r->z, &Z); @@ -231,43 +219,35 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons /* Correct for wNAF skew */ secp256k1_ge correction = *a; secp256k1_ge_storage correction_1_stor; -#ifdef USE_ENDOMORPHISM secp256k1_ge_storage correction_lam_stor; -#endif secp256k1_ge_storage a2_stor; secp256k1_gej tmpj; secp256k1_gej_set_ge(&tmpj, &correction); secp256k1_gej_double_var(&tmpj, &tmpj, NULL); secp256k1_ge_set_gej(&correction, &tmpj); secp256k1_ge_to_storage(&correction_1_stor, a); -#ifdef USE_ENDOMORPHISM if (size > 128) { secp256k1_ge_to_storage(&correction_lam_stor, a); } -#endif secp256k1_ge_to_storage(&a2_stor, &correction); /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); -#ifdef USE_ENDOMORPHISM if (size > 128) { secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); } -#endif /* Apply the correction */ secp256k1_ge_from_storage(&correction, &correction_1_stor); secp256k1_ge_neg(&correction, &correction); secp256k1_gej_add_ge(r, r, &correction); -#ifdef USE_ENDOMORPHISM if (size > 128) { secp256k1_ge_from_storage(&correction, &correction_lam_stor); secp256k1_ge_neg(&correction, &correction); secp256k1_ge_mul_lambda(&correction, &correction); secp256k1_gej_add_ge(r, r, &correction); } -#endif } } diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h index f03fa9469d..a9e8b3c76c 100644 --- a/src/secp256k1/src/ecmult_impl.h +++ b/src/secp256k1/src/ecmult_impl.h @@ -38,8 +38,8 @@ * (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes, * where sizeof(secp256k1_ge_storage) is typically 64 bytes but can * be larger due to platform-specific padding and alignment. - * If the endomorphism optimization is enabled (USE_ENDOMORMPHSIM) - * two tables of this size are used instead of only one. + * Two tables of this size are used (due to the endomorphism + * optimization). */ # define WINDOW_G ECMULT_WINDOW_SIZE #endif @@ -59,11 +59,7 @@ # error Set ECMULT_WINDOW_SIZE to an integer in range [2..24]. #endif -#ifdef USE_ENDOMORPHISM - #define WNAF_BITS 128 -#else - #define WNAF_BITS 256 -#endif +#define WNAF_BITS 128 #define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w)) #define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w) @@ -77,17 +73,9 @@ #define PIPPENGER_MAX_BUCKET_WINDOW 12 /* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */ -#ifdef USE_ENDOMORPHISM - #define ECMULT_PIPPENGER_THRESHOLD 88 -#else - #define ECMULT_PIPPENGER_THRESHOLD 160 -#endif +#define ECMULT_PIPPENGER_THRESHOLD 88 -#ifdef USE_ENDOMORPHISM - #define ECMULT_MAX_POINTS_PER_BATCH 5000000 -#else - #define ECMULT_MAX_POINTS_PER_BATCH 10000000 -#endif +#define ECMULT_MAX_POINTS_PER_BATCH 5000000 /** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will @@ -313,16 +301,12 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25 static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE = ROUND_TO_ALIGN(sizeof((*((secp256k1_ecmult_context*) NULL)->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)) -#ifdef USE_ENDOMORPHISM + ROUND_TO_ALIGN(sizeof((*((secp256k1_ecmult_context*) NULL)->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)) -#endif ; static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { ctx->pre_g = NULL; -#ifdef USE_ENDOMORPHISM ctx->pre_g_128 = NULL; -#endif } static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc) { @@ -347,7 +331,6 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void * /* precompute the tables with odd multiples */ secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj); -#ifdef USE_ENDOMORPHISM { secp256k1_gej g_128j; int i; @@ -364,7 +347,6 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void * } secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j); } -#endif } static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src) { @@ -372,11 +354,9 @@ static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *d /* We cast to void* first to suppress a -Wcast-align warning. */ dst->pre_g = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src)); } -#ifdef USE_ENDOMORPHISM if (src->pre_g_128 != NULL) { dst->pre_g_128 = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src)); } -#endif } static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { @@ -447,16 +427,11 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, } struct secp256k1_strauss_point_state { -#ifdef USE_ENDOMORPHISM secp256k1_scalar na_1, na_lam; - int wnaf_na_1[130]; - int wnaf_na_lam[130]; + int wnaf_na_1[129]; + int wnaf_na_lam[129]; int bits_na_1; int bits_na_lam; -#else - int wnaf_na[256]; - int bits_na; -#endif size_t input_pos; }; @@ -464,58 +439,43 @@ struct secp256k1_strauss_state { secp256k1_gej* prej; secp256k1_fe* zr; secp256k1_ge* pre_a; -#ifdef USE_ENDOMORPHISM secp256k1_ge* pre_a_lam; -#endif struct secp256k1_strauss_point_state* ps; }; -static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, const struct secp256k1_strauss_state *state, secp256k1_gej *r, int num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { +static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, const struct secp256k1_strauss_state *state, secp256k1_gej *r, size_t num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { secp256k1_ge tmpa; secp256k1_fe Z; -#ifdef USE_ENDOMORPHISM /* Splitted G factors. */ secp256k1_scalar ng_1, ng_128; int wnaf_ng_1[129]; int bits_ng_1 = 0; int wnaf_ng_128[129]; int bits_ng_128 = 0; -#else - int wnaf_ng[256]; - int bits_ng = 0; -#endif int i; int bits = 0; - int np; - int no = 0; + size_t np; + size_t no = 0; for (np = 0; np < num; ++np) { if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) { continue; } state->ps[no].input_pos = np; -#ifdef USE_ENDOMORPHISM /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ secp256k1_scalar_split_lambda(&state->ps[no].na_1, &state->ps[no].na_lam, &na[np]); /* build wnaf representation for na_1 and na_lam. */ - state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 130, &state->ps[no].na_1, WINDOW_A); - state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 130, &state->ps[no].na_lam, WINDOW_A); - VERIFY_CHECK(state->ps[no].bits_na_1 <= 130); - VERIFY_CHECK(state->ps[no].bits_na_lam <= 130); + state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &state->ps[no].na_1, WINDOW_A); + state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &state->ps[no].na_lam, WINDOW_A); + VERIFY_CHECK(state->ps[no].bits_na_1 <= 129); + VERIFY_CHECK(state->ps[no].bits_na_lam <= 129); if (state->ps[no].bits_na_1 > bits) { bits = state->ps[no].bits_na_1; } if (state->ps[no].bits_na_lam > bits) { bits = state->ps[no].bits_na_lam; } -#else - /* build wnaf representation for na. */ - state->ps[no].bits_na = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na, 256, &na[np], WINDOW_A); - if (state->ps[no].bits_na > bits) { - bits = state->ps[no].bits_na; - } -#endif ++no; } @@ -547,7 +507,6 @@ static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, c secp256k1_fe_set_int(&Z, 1); } -#ifdef USE_ENDOMORPHISM for (np = 0; np < no; ++np) { for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { secp256k1_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]); @@ -568,21 +527,12 @@ static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, c bits = bits_ng_128; } } -#else - if (ng) { - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); - if (bits_ng > bits) { - bits = bits_ng; - } - } -#endif secp256k1_gej_set_infinity(r); for (i = bits - 1; i >= 0; i--) { int n; secp256k1_gej_double_var(r, r, NULL); -#ifdef USE_ENDOMORPHISM for (np = 0; np < no; ++np) { if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) { ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); @@ -601,18 +551,6 @@ static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, c ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } -#else - for (np = 0; np < no; ++np) { - if (i < state->ps[np].bits_na && (n = state->ps[np].wnaf_na[i])) { - ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A); - secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); - } - } - if (i < bits_ng && (n = wnaf_ng[i])) { - ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); - } -#endif } if (!r->infinity) { @@ -625,27 +563,19 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; struct secp256k1_strauss_point_state ps[1]; -#ifdef USE_ENDOMORPHISM secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; -#endif struct secp256k1_strauss_state state; state.prej = prej; state.zr = zr; state.pre_a = pre_a; -#ifdef USE_ENDOMORPHISM state.pre_a_lam = pre_a_lam; -#endif state.ps = ps; secp256k1_ecmult_strauss_wnaf(ctx, &state, r, 1, a, na, ng); } static size_t secp256k1_strauss_scratch_size(size_t n_points) { -#ifdef USE_ENDOMORPHISM static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); -#else - static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar); -#endif return n_points*point_size; } @@ -665,12 +595,8 @@ static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callba scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar)); state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej)); state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe)); -#ifdef USE_ENDOMORPHISM state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A); -#else - state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge)); -#endif state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state)); if (points == NULL || scalars == NULL || state.prej == NULL || state.zr == NULL || state.pre_a == NULL) { @@ -868,7 +794,6 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi * set of buckets) for a given number of points. */ static int secp256k1_pippenger_bucket_window(size_t n) { -#ifdef USE_ENDOMORPHISM if (n <= 1) { return 1; } else if (n <= 4) { @@ -892,33 +817,6 @@ static int secp256k1_pippenger_bucket_window(size_t n) { } else { return PIPPENGER_MAX_BUCKET_WINDOW; } -#else - if (n <= 1) { - return 1; - } else if (n <= 11) { - return 2; - } else if (n <= 45) { - return 3; - } else if (n <= 100) { - return 4; - } else if (n <= 275) { - return 5; - } else if (n <= 625) { - return 6; - } else if (n <= 1850) { - return 7; - } else if (n <= 3400) { - return 8; - } else if (n <= 9630) { - return 9; - } else if (n <= 17900) { - return 10; - } else if (n <= 32800) { - return 11; - } else { - return PIPPENGER_MAX_BUCKET_WINDOW; - } -#endif } /** @@ -926,7 +824,6 @@ static int secp256k1_pippenger_bucket_window(size_t n) { */ static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) { switch(bucket_window) { -#ifdef USE_ENDOMORPHISM case 1: return 1; case 2: return 4; case 3: return 20; @@ -939,26 +836,11 @@ static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) { case 10: return 7880; case 11: return 16050; case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; -#else - case 1: return 1; - case 2: return 11; - case 3: return 45; - case 4: return 100; - case 5: return 275; - case 6: return 625; - case 7: return 1850; - case 8: return 3400; - case 9: return 9630; - case 10: return 17900; - case 11: return 32800; - case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX; -#endif } return 0; } -#ifdef USE_ENDOMORPHISM SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, secp256k1_scalar *s2, secp256k1_ge *p1, secp256k1_ge *p2) { secp256k1_scalar tmp = *s1; secp256k1_scalar_split_lambda(s1, s2, &tmp); @@ -973,32 +855,23 @@ SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, s secp256k1_ge_neg(p2, p2); } } -#endif /** * Returns the scratch size required for a given number of points (excluding * base point G) without considering alignment. */ static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_window) { -#ifdef USE_ENDOMORPHISM size_t entries = 2*n_points + 2; -#else - size_t entries = n_points + 1; -#endif size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size; } static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) { const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch); - /* Use 2(n+1) with the endomorphism, n+1 without, when calculating batch + /* Use 2(n+1) with the endomorphism, when calculating batch * sizes. The reason for +1 is that we add the G scalar to the list of * other scalars. */ -#ifdef USE_ENDOMORPHISM size_t entries = 2*n_points + 2; -#else - size_t entries = n_points + 1; -#endif secp256k1_ge *points; secp256k1_scalar *scalars; secp256k1_gej *buckets; @@ -1035,10 +908,8 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call scalars[0] = *inp_g_sc; points[0] = secp256k1_ge_const_g; idx++; -#ifdef USE_ENDOMORPHISM secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]); idx++; -#endif } while (point_idx < n_points) { @@ -1047,10 +918,8 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call return 0; } idx++; -#ifdef USE_ENDOMORPHISM secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]); idx++; -#endif point_idx++; } @@ -1093,9 +962,7 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal size_t space_overhead; size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int); -#ifdef USE_ENDOMORPHISM entry_size = 2*entry_size; -#endif space_overhead = (sizeof(secp256k1_gej) << bucket_window) + entry_size + sizeof(struct secp256k1_pippenger_state); if (space_overhead > max_alloc) { break; diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h index 6185be052d..36e39ecf0f 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/src/group.h @@ -59,6 +59,7 @@ static int secp256k1_ge_is_infinity(const secp256k1_ge *a); /** Check whether a group element is valid (i.e., on the curve). */ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); /** Set a group element equal to another which is given in jacobian coordinates */ @@ -115,10 +116,8 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c /** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); -#ifdef USE_ENDOMORPHISM /** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); -#endif /** Clear a secp256k1_gej to prevent leaking sensitive information. */ static void secp256k1_gej_clear(secp256k1_gej *r); @@ -138,4 +137,15 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); +/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. + * + * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the + * group, and this function returns always true. + * + * When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a + * (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this + * function checks whether a point that is on the curve is in fact also in that subgroup. + */ +static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); + #endif /* SECP256K1_GROUP_H */ diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index ccd93d3483..a5fbc91a0f 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/src/group_impl.h @@ -11,49 +11,38 @@ #include "field.h" #include "group.h" -/* These points can be generated in sage as follows: +/* These exhaustive group test orders and generators are chosen such that: + * - The field size is equal to that of secp256k1, so field code is the same. + * - The curve equation is of the form y^2=x^3+B for some constant B. + * - The subgroup has a generator 2*P, where P.x=1. + * - The subgroup has size less than 1000 to permit exhaustive testing. + * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). * - * 0. Setup a worksheet with the following parameters. - * b = 4 # whatever CURVE_B will be set to - * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) - * C = EllipticCurve ([F (0), F (b)]) - * - * 1. Determine all the small orders available to you. (If there are - * no satisfactory ones, go back and change b.) - * print C.order().factor(limit=1000) - * - * 2. Choose an order as one of the prime factors listed in the above step. - * (You can also multiply some to get a composite order, though the - * tests will crash trying to invert scalars during signing.) We take a - * random point and scale it to drop its order to the desired value. - * There is some probability this won't work; just try again. - * order = 199 - * P = C.random_point() - * P = (int(P.order()) / int(order)) * P - * assert(P.order() == order) - * - * 3. Print the values. You'll need to use a vim macro or something to - * split the hex output into 4-byte chunks. - * print "%x %x" % P.xy() + * These parameters are generated using sage/gen_exhaustive_groups.sage. */ #if defined(EXHAUSTIVE_TEST_ORDER) -# if EXHAUSTIVE_TEST_ORDER == 199 +# if EXHAUSTIVE_TEST_ORDER == 13 static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069, - 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18, - 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868, - 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED + 0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f, + 0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb, + 0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2, + 0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24 ); - -static const int CURVE_B = 4; -# elif EXHAUSTIVE_TEST_ORDER == 13 +static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( + 0x3d3486b2, 0x159a9ca5, 0xc75638be, 0xb23a69bc, + 0x946a45ab, 0x24801247, 0xb4ed2b8e, 0x26b6a417 +); +# elif EXHAUSTIVE_TEST_ORDER == 199 static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( - 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0, - 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15, - 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e, - 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac + 0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9, + 0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18, + 0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c, + 0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae +); +static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( + 0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1, + 0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb ); -static const int CURVE_B = 2; # else # error No known generator for the specified exhaustive test group order. # endif @@ -68,7 +57,7 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL ); -static const int CURVE_B = 7; +static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7); #endif static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { @@ -219,14 +208,13 @@ static void secp256k1_ge_clear(secp256k1_ge *r) { } static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) { - secp256k1_fe x2, x3, c; + secp256k1_fe x2, x3; r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; - secp256k1_fe_set_int(&c, CURVE_B); - secp256k1_fe_add(&c, &x3); - return secp256k1_fe_sqrt(&r->y, &c); + secp256k1_fe_add(&x3, &secp256k1_fe_const_b); + return secp256k1_fe_sqrt(&r->y, &x3); } static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { @@ -269,36 +257,15 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { return a->infinity; } -static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { - secp256k1_fe y2, x3, z2, z6; - if (a->infinity) { - return 0; - } - /** y^2 = x^3 + 7 - * (Y/Z^3)^2 = (X/Z^2)^3 + 7 - * Y^2 / Z^6 = X^3 / Z^6 + 7 - * Y^2 = X^3 + 7*Z^6 - */ - secp256k1_fe_sqr(&y2, &a->y); - secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_sqr(&z2, &a->z); - secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); - secp256k1_fe_mul_int(&z6, CURVE_B); - secp256k1_fe_add(&x3, &z6); - secp256k1_fe_normalize_weak(&x3); - return secp256k1_fe_equal_var(&y2, &x3); -} - static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { - secp256k1_fe y2, x3, c; + secp256k1_fe y2, x3; if (a->infinity) { return 0; } /* y^2 = x^3 + 7 */ secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_set_int(&c, CURVE_B); - secp256k1_fe_add(&x3, &c); + secp256k1_fe_add(&x3, &secp256k1_fe_const_b); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); } @@ -679,7 +646,6 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, secp256k1_fe_storage_cmov(&r->y, &a->y, flag); } -#ifdef USE_ENDOMORPHISM static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { static const secp256k1_fe beta = SECP256K1_FE_CONST( 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, @@ -688,7 +654,6 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { *r = *a; secp256k1_fe_mul(&r->x, &r->x, &beta); } -#endif static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { secp256k1_fe yz; @@ -704,4 +669,25 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { return secp256k1_fe_is_quad_var(&yz); } +static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { +#ifdef EXHAUSTIVE_TEST_ORDER + secp256k1_gej out; + int i; + + /* A very simple EC multiplication ladder that avoids a dependecy on ecmult. */ + secp256k1_gej_set_infinity(&out); + for (i = 0; i < 32; ++i) { + secp256k1_gej_double_var(&out, &out, NULL); + if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) { + secp256k1_gej_add_ge_var(&out, &out, ge, NULL); + } + } + return secp256k1_gej_is_infinity(&out); +#else + (void)ge; + /* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */ + return 1; +#endif +} + #endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h index fe26e8fb69..e8d2aeab9a 100644 --- a/src/secp256k1/src/modules/ecdh/tests_impl.h +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -80,7 +80,7 @@ void test_ecdh_generator_basepoint(void) { /* compute "explicitly" */ CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); /* compare */ - CHECK(memcmp(output_ecdh, point_ser, 65) == 0); + CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0); /* compute using ECDH function with default hash function */ CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); @@ -90,7 +90,7 @@ void test_ecdh_generator_basepoint(void) { secp256k1_sha256_write(&sha, point_ser, point_ser_len); secp256k1_sha256_finalize(&sha, output_ser); /* compare */ - CHECK(memcmp(output_ecdh, output_ser, 32) == 0); + CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0); } } diff --git a/src/secp256k1/src/modules/extrakeys/Makefile.am.include b/src/secp256k1/src/modules/extrakeys/Makefile.am.include index 8515f92e7a..0d901ec1f4 100644 --- a/src/secp256k1/src/modules/extrakeys/Makefile.am.include +++ b/src/secp256k1/src/modules/extrakeys/Makefile.am.include @@ -1,3 +1,4 @@ include_HEADERS += include/secp256k1_extrakeys.h noinst_HEADERS += src/modules/extrakeys/tests_impl.h +noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h noinst_HEADERS += src/modules/extrakeys/main_impl.h diff --git a/src/secp256k1/src/modules/extrakeys/main_impl.h b/src/secp256k1/src/modules/extrakeys/main_impl.h index d319215355..5378d2f301 100644 --- a/src/secp256k1/src/modules/extrakeys/main_impl.h +++ b/src/secp256k1/src/modules/extrakeys/main_impl.h @@ -33,6 +33,9 @@ int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_p if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) { return 0; } + if (!secp256k1_ge_is_in_correct_subgroup(&pk)) { + return 0; + } secp256k1_xonly_pubkey_save(pubkey, &pk); return 1; } @@ -121,7 +124,7 @@ int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const u secp256k1_fe_normalize_var(&pk.y); secp256k1_fe_get_b32(pk_expected32, &pk.x); - return memcmp(&pk_expected32, tweaked_pubkey32, 32) == 0 + return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0 && secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity; } diff --git a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h new file mode 100644 index 0000000000..0e29bc6b09 --- /dev/null +++ b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h @@ -0,0 +1,68 @@ +/********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_ +#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_ + +#include "src/modules/extrakeys/main_impl.h" +#include "include/secp256k1_extrakeys.h" + +static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) { + secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + int parities[EXHAUSTIVE_TEST_ORDER - 1]; + unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; + int i; + + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_fe fe; + secp256k1_scalar scalar_i; + unsigned char buf[33]; + int parity; + + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(buf, &scalar_i); + + /* Construct pubkey and keypair. */ + CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf)); + + /* Construct serialized xonly_pubkey from keypair. */ + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + + /* Parse the xonly_pubkey back and verify it matches the previously serialized value. */ + CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */ + CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1])); + CHECK(parity == parities[i - 1]); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0); + + /* Compare the xonly_pubkey bytes against the precomputed group. */ + secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]); + CHECK(secp256k1_fe_equal_var(&fe, &group[i].x)); + + /* Check the parity against the precomputed group. */ + fe = group[i].y; + secp256k1_fe_normalize_var(&fe); + CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]); + + /* Verify that the higher half is identical to the lower half mirrored. */ + if (i > EXHAUSTIVE_TEST_ORDER / 2) { + CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0); + CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]); + } + } + + /* TODO: keypair/xonly_pubkey tweak tests */ +} + +#endif diff --git a/src/secp256k1/src/modules/extrakeys/tests_impl.h b/src/secp256k1/src/modules/extrakeys/tests_impl.h index fc9d40eda1..5ee135849e 100644 --- a/src/secp256k1/src/modules/extrakeys/tests_impl.h +++ b/src/secp256k1/src/modules/extrakeys/tests_impl.h @@ -35,9 +35,9 @@ void test_xonly_pubkey(void) { secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount); secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); - secp256k1_rand256(sk); + secp256k1_testrand256(sk); memset(ones32, 0xFF, 32); - secp256k1_rand256(xy_sk); + secp256k1_testrand256(xy_sk); CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); @@ -60,7 +60,7 @@ void test_xonly_pubkey(void) { sk[0] = 1; CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(memcmp(&pk, &xonly_pk, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); CHECK(pk_parity == 0); /* Choose a secret key such that pubkey and xonly_pubkey are each others @@ -68,7 +68,7 @@ void test_xonly_pubkey(void) { sk[0] = 2; CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(memcmp(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); CHECK(pk_parity == 1); secp256k1_pubkey_load(ctx, &pk1, &pk); secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk); @@ -81,7 +81,7 @@ void test_xonly_pubkey(void) { CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0); CHECK(ecount == 1); CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0); - CHECK(memcmp(buf32, zeros64, 32) == 0); + CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); CHECK(ecount == 2); { /* A pubkey filled with 0s will fail to serialize due to pubkey_load @@ -104,28 +104,28 @@ void test_xonly_pubkey(void) { CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1); - CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); /* Test parsing invalid field elements */ memset(&xonly_pk, 1, sizeof(xonly_pk)); /* Overflowing field element */ CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0); - CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); memset(&xonly_pk, 1, sizeof(xonly_pk)); /* There's no point with x-coordinate 0 on secp256k1 */ CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0); - CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); /* If a random 32-byte string can not be parsed with ec_pubkey_parse * (because interpreted as X coordinate it does not correspond to a point on * the curve) then xonly_pubkey_parse should fail as well. */ for (i = 0; i < count; i++) { unsigned char rand33[33]; - secp256k1_rand256(&rand33[1]); + secp256k1_testrand256(&rand33[1]); rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) { memset(&xonly_pk, 1, sizeof(xonly_pk)); CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0); - CHECK(memcmp(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); } else { CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1); } @@ -154,8 +154,8 @@ void test_xonly_pubkey_tweak(void) { secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); memset(overflows, 0xff, sizeof(overflows)); - secp256k1_rand256(tweak); - secp256k1_rand256(sk); + secp256k1_testrand256(tweak); + secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); @@ -170,15 +170,15 @@ void test_xonly_pubkey_tweak(void) { CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0); CHECK(ecount == 4); /* NULL internal_xonly_pk zeroes the output_pk */ - CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, NULL) == 0); CHECK(ecount == 5); /* NULL tweak zeroes the output_pk */ - CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); /* Invalid tweak zeroes the output_pk */ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0); - CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); /* A zero tweak is fine */ CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1); @@ -193,16 +193,16 @@ void test_xonly_pubkey_tweak(void) { secp256k1_scalar_get_b32(tweak, &scalar_tweak); CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0) || (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0)); - CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); } /* Invalid pk with a valid tweak */ memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); - secp256k1_rand256(tweak); + secp256k1_testrand256(tweak); ecount = 0; CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0); CHECK(ecount == 1); - CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); secp256k1_context_destroy(none); secp256k1_context_destroy(sign); @@ -228,8 +228,8 @@ void test_xonly_pubkey_tweak_check(void) { secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); memset(overflows, 0xff, sizeof(overflows)); - secp256k1_rand256(tweak); - secp256k1_rand256(sk); + secp256k1_testrand256(tweak); + secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); @@ -268,7 +268,7 @@ void test_xonly_pubkey_tweak_check(void) { /* Overflowing tweak not allowed */ CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0); - CHECK(memcmp(&output_pk, zeros64, sizeof(output_pk)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(ecount == 5); secp256k1_context_destroy(none); @@ -287,7 +287,7 @@ void test_xonly_pubkey_tweak_recursive(void) { unsigned char tweak[N_PUBKEYS - 1][32]; int i; - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1); /* Add tweaks */ for (i = 0; i < N_PUBKEYS - 1; i++) { @@ -327,51 +327,51 @@ void test_keypair(void) { /* Test keypair_create */ ecount = 0; - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(none, &keypair, sk) == 0); - CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 1); CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 0); - CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 2); CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0); CHECK(ecount == 3); CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0); - CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(ecount == 4); /* Invalid secret key */ CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0); - CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0); - CHECK(memcmp(zeros96, &keypair, sizeof(keypair)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); /* Test keypair_pub */ ecount = 0; - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1); CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0); CHECK(ecount == 1); CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0); CHECK(ecount == 2); - CHECK(memcmp(zeros96, &pk, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); /* Using an invalid keypair is fine for keypair_pub */ memset(&keypair, 0, sizeof(keypair)); CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1); - CHECK(memcmp(zeros96, &pk, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); /* keypair holds the same pubkey as pubkey_create */ CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1); CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1); - CHECK(memcmp(&pk, &pk_tmp, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); /** Test keypair_xonly_pub **/ ecount = 0; - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0); @@ -379,13 +379,13 @@ void test_keypair(void) { CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0); CHECK(ecount == 2); - CHECK(memcmp(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); /* Using an invalid keypair will set the xonly_pk to 0 (first reset * xonly_pk). */ CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 1); memset(&keypair, 0, sizeof(keypair)); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0); - CHECK(memcmp(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); + CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); CHECK(ecount == 3); /** keypair holds the same xonly pubkey as pubkey_create **/ @@ -393,7 +393,7 @@ void test_keypair(void) { CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); - CHECK(memcmp(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); CHECK(pk_parity == pk_parity_tmp); secp256k1_context_destroy(none); @@ -414,8 +414,8 @@ void test_keypair_add(void) { secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount); CHECK(sizeof(zeros96) == sizeof(keypair)); - secp256k1_rand256(sk); - secp256k1_rand256(tweak); + secp256k1_testrand256(sk); + secp256k1_testrand256(tweak); memset(overflows, 0xFF, 32); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); @@ -429,12 +429,12 @@ void test_keypair_add(void) { CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0); CHECK(ecount == 4); /* This does not set the keypair to zeroes */ - CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) != 0); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); /* Invalid tweak zeroes the keypair */ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0); - CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); /* A zero tweak is fine */ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); @@ -444,7 +444,7 @@ void test_keypair_add(void) { for (i = 0; i < count; i++) { secp256k1_scalar scalar_tweak; secp256k1_keypair keypair_tmp; - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); memcpy(&keypair_tmp, &keypair, sizeof(keypair)); /* Because sk may be negated before adding, we need to try with tweak = @@ -454,17 +454,17 @@ void test_keypair_add(void) { secp256k1_scalar_get_b32(tweak, &scalar_tweak); CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0) || (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0)); - CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0 - || memcmp(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 + || secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); } /* Invalid keypair with a valid tweak */ memset(&keypair, 0, sizeof(keypair)); - secp256k1_rand256(tweak); + secp256k1_testrand256(tweak); ecount = 0; CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0); CHECK(ecount == 1); - CHECK(memcmp(&keypair, zeros96, sizeof(keypair)) == 0); + CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); /* Only seckey part of keypair invalid */ CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); memset(&keypair, 0, 32); @@ -486,7 +486,7 @@ void test_keypair_add(void) { unsigned char pk32[32]; int pk_parity; - secp256k1_rand256(tweak); + secp256k1_testrand256(tweak); CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1); @@ -498,11 +498,11 @@ void test_keypair_add(void) { /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1); - CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); /* Check that the secret key in the keypair is tweaked correctly */ CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1); - CHECK(memcmp(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); + CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); } secp256k1_context_destroy(none); secp256k1_context_destroy(sign); diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include index bf23c26e71..e2d3f1248d 100644 --- a/src/secp256k1/src/modules/recovery/Makefile.am.include +++ b/src/secp256k1/src/modules/recovery/Makefile.am.include @@ -1,6 +1,7 @@ include_HEADERS += include/secp256k1_recovery.h noinst_HEADERS += src/modules/recovery/main_impl.h noinst_HEADERS += src/modules/recovery/tests_impl.h +noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h if USE_BENCHMARK noinst_PROGRAMS += bench_recover bench_recover_SOURCES = src/bench_recover.c diff --git a/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h b/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h new file mode 100644 index 0000000000..a2f381d77a --- /dev/null +++ b/src/secp256k1/src/modules/recovery/tests_exhaustive_impl.h @@ -0,0 +1,149 @@ +/********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H +#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H + +#include "src/modules/recovery/main_impl.h" +#include "include/secp256k1_recovery.h" + +void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j, k; + uint64_t iter = 0; + + /* Loop */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ + if (skip_section(&iter)) continue; + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ + const int starting_k = k; + secp256k1_fe r_dot_y_normalized; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + int expected_recid; + int recid; + int overflow; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + /* Check directly */ + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + r_from_k(&expected_r, group, k, &overflow); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + /* The recid's second bit is for conveying overflow (R.x value >= group order). + * In the actual secp256k1 this is an astronomically unlikely event, but in the + * small group used here, it will be the case for all points except the ones where + * R.x=1 (which the group is specifically selected to have). + * Note that this isn't actually useful; full recovery would need to convey + * floor(R.x / group_order), but only one bit is used as that is sufficient + * in the real group. */ + expected_recid = overflow ? 2 : 0; + r_dot_y_normalized = group[k].y; + secp256k1_fe_normalize(&r_dot_y_normalized); + /* Also the recovery id is flipped depending if we hit the low-s branch */ + if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) { + expected_recid |= secp256k1_fe_is_odd(&r_dot_y_normalized); + } else { + expected_recid |= !secp256k1_fe_is_odd(&r_dot_y_normalized); + } + CHECK(recid == expected_recid); + + /* Convert to a standard sig then check */ + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k, NULL); + CHECK(r == expected_r); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } +} + +void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { + /* This is essentially a copy of test_exhaustive_verify, with recovery added */ + int s, r, msg, key; + uint64_t iter = 0; + for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { + for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { + for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { + for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int recid = 0; + int k, should_verify; + unsigned char msg32[32]; + + if (skip_section(&iter)) continue; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + secp256k1_scalar_get_b32(msg32, &msg_s); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k, NULL); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* We would like to try recovering the pubkey and checking that it matches, + * but pubkey recovery is impossible in the exhaustive tests (the reason + * being that there are 12 nonzero r values, 12 nonzero points, and no + * overlap between the sets, so there are no valid signatures). */ + + /* Verify by converting to a standard signature and calling verify */ + secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +static void test_exhaustive_recovery(const secp256k1_context *ctx, const secp256k1_ge *group) { + test_exhaustive_recovery_sign(ctx, group); + test_exhaustive_recovery_verify(ctx, group); +} + +#endif /* SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H */ diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h index 38a533a755..09cae38403 100644 --- a/src/secp256k1/src/modules/recovery/tests_impl.h +++ b/src/secp256k1/src/modules/recovery/tests_impl.h @@ -25,7 +25,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c } /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ memset(nonce32, 1, 32); - return secp256k1_rand_bits(1); + return secp256k1_testrand_bits(1); } void test_ecdsa_recovery_api(void) { @@ -184,7 +184,7 @@ void test_ecdsa_recovery_end_to_end(void) { CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); - CHECK(memcmp(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0); CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); memset(&rsignature[4], 0, sizeof(rsignature[4])); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); @@ -193,16 +193,16 @@ void test_ecdsa_recovery_end_to_end(void) { /* Parse compact (with recovery id) and recover. */ CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); - CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); /* Serialize/destroy/parse signature and verify again. */ CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); - sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + sig[secp256k1_testrand_bits(6)] += 1 + secp256k1_testrand_int(255); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); /* Recover again */ CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || - memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); + secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0); } /* Tests several edge cases. */ diff --git a/src/secp256k1/src/modules/schnorrsig/Makefile.am.include b/src/secp256k1/src/modules/schnorrsig/Makefile.am.include index a82bafe43f..568bcc3523 100644 --- a/src/secp256k1/src/modules/schnorrsig/Makefile.am.include +++ b/src/secp256k1/src/modules/schnorrsig/Makefile.am.include @@ -1,6 +1,7 @@ include_HEADERS += include/secp256k1_schnorrsig.h noinst_HEADERS += src/modules/schnorrsig/main_impl.h noinst_HEADERS += src/modules/schnorrsig/tests_impl.h +noinst_HEADERS += src/modules/schnorrsig/tests_exhaustive_impl.h if USE_BENCHMARK noinst_PROGRAMS += bench_schnorrsig bench_schnorrsig_SOURCES = src/bench_schnorrsig.c diff --git a/src/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h index a0218f881a..b0d8481f9b 100644 --- a/src/secp256k1/src/modules/schnorrsig/main_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/main_impl.h @@ -68,7 +68,7 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms /* Tag the hash with algo16 which is important to avoid nonce reuse across * algorithms. If this nonce function is used in BIP-340 signing as defined * in the spec, an optimized tagging implementation is used. */ - if (memcmp(algo16, bip340_algo16, 16) == 0) { + if (secp256k1_memcmp_var(algo16, bip340_algo16, 16) == 0) { secp256k1_nonce_function_bip340_sha256_tagged(&sha); } else { int algo16_len = 16; @@ -108,6 +108,22 @@ static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { sha->bytes = 64; } +static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg32, const unsigned char *pubkey32) +{ + unsigned char buf[32]; + secp256k1_sha256 sha; + + /* tagged hash(r.x, pk.x, msg32) */ + secp256k1_schnorrsig_sha256_tagged(&sha); + secp256k1_sha256_write(&sha, r32, 32); + secp256k1_sha256_write(&sha, pubkey32, 32); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, buf); + /* Set scalar e to the challenge hash modulo the curve order as per + * BIP340. */ + secp256k1_scalar_set_b32(e, buf, NULL); +} + int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) { secp256k1_scalar sk; secp256k1_scalar e; @@ -115,7 +131,6 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64 secp256k1_gej rj; secp256k1_ge pk; secp256k1_ge r; - secp256k1_sha256 sha; unsigned char buf[32] = { 0 }; unsigned char pk_buf[32]; unsigned char seckey[32]; @@ -159,16 +174,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64 secp256k1_fe_normalize_var(&r.x); secp256k1_fe_get_b32(&sig64[0], &r.x); - /* tagged hash(r.x, pk.x, msg32) */ - secp256k1_schnorrsig_sha256_tagged(&sha); - secp256k1_sha256_write(&sha, &sig64[0], 32); - secp256k1_sha256_write(&sha, pk_buf, sizeof(pk_buf)); - secp256k1_sha256_write(&sha, msg32, 32); - secp256k1_sha256_finalize(&sha, buf); - - /* Set scalar e to the challenge hash modulo the curve order as per - * BIP340. */ - secp256k1_scalar_set_b32(&e, buf, NULL); + secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, pk_buf); secp256k1_scalar_mul(&e, &e, &sk); secp256k1_scalar_add(&e, &e, &k); secp256k1_scalar_get_b32(&sig64[32], &e); @@ -189,7 +195,6 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha secp256k1_gej pkj; secp256k1_fe rx; secp256k1_ge r; - secp256k1_sha256 sha; unsigned char buf[32]; int overflow; @@ -212,13 +217,9 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha return 0; } - secp256k1_schnorrsig_sha256_tagged(&sha); - secp256k1_sha256_write(&sha, &sig64[0], 32); + /* Compute e. */ secp256k1_fe_get_b32(buf, &pk.x); - secp256k1_sha256_write(&sha, buf, sizeof(buf)); - secp256k1_sha256_write(&sha, msg32, 32); - secp256k1_sha256_finalize(&sha, buf); - secp256k1_scalar_set_b32(&e, buf, NULL); + secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, buf); /* Compute rj = s*G + (-e)*pkj */ secp256k1_scalar_negate(&e, &e); diff --git a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h new file mode 100644 index 0000000000..4bf0bc1680 --- /dev/null +++ b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -0,0 +1,206 @@ +/********************************************************************** + * Copyright (c) 2020 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_ +#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_ + +#include "include/secp256k1_schnorrsig.h" +#include "src/modules/schnorrsig/main_impl.h" + +static const unsigned char invalid_pubkey_bytes[][32] = { + /* 0 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + /* 2 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 + }, + /* order */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 24) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 16) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 0UL) >> 8) & 0xFF, + (EXHAUSTIVE_TEST_ORDER + 0UL) & 0xFF + }, + /* order + 1 */ + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 24) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 16) & 0xFF, + ((EXHAUSTIVE_TEST_ORDER + 1UL) >> 8) & 0xFF, + (EXHAUSTIVE_TEST_ORDER + 1UL) & 0xFF + }, + /* field size */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F + }, + /* field size + 1 (note that 1 is legal) */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 + }, + /* 2^256 - 1 */ + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + } +}; + +#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0])) + +static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, + const unsigned char *key32, const unsigned char *xonly_pk32, + const unsigned char *algo16, void* data) { + secp256k1_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)xonly_pk32; + (void)algo16; + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) { + int d; + uint64_t iter = 0; + /* Iterate over the possible public keys to verify against (through their corresponding DL d). */ + for (d = 1; d <= EXHAUSTIVE_TEST_ORDER / 2; ++d) { + int actual_d; + unsigned k; + unsigned char pk32[32]; + memcpy(pk32, xonly_pubkey_bytes[d - 1], 32); + actual_d = parities[d - 1] ? EXHAUSTIVE_TEST_ORDER - d : d; + /* Iterate over the possible valid first 32 bytes in the signature, through their corresponding DL k. + Values above EXHAUSTIVE_TEST_ORDER/2 refer to the entries in invalid_pubkey_bytes. */ + for (k = 1; k <= EXHAUSTIVE_TEST_ORDER / 2 + NUM_INVALID_KEYS; ++k) { + unsigned char sig64[64]; + int actual_k = -1; + int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; + int e_count_done = 0; + if (skip_section(&iter)) continue; + if (k <= EXHAUSTIVE_TEST_ORDER / 2) { + memcpy(sig64, xonly_pubkey_bytes[k - 1], 32); + actual_k = parities[k - 1] ? EXHAUSTIVE_TEST_ORDER - k : k; + } else { + memcpy(sig64, invalid_pubkey_bytes[k - 1 - EXHAUSTIVE_TEST_ORDER / 2], 32); + } + /* Randomly generate messages until all challenges have been hit. */ + while (e_count_done < EXHAUSTIVE_TEST_ORDER) { + secp256k1_scalar e; + unsigned char msg32[32]; + secp256k1_testrand256(msg32); + secp256k1_schnorrsig_challenge(&e, sig64, msg32, pk32); + /* Only do work if we hit a challenge we haven't tried before. */ + if (!e_done[e]) { + /* Iterate over the possible valid last 32 bytes in the signature. + 0..order=that s value; order+1=random bytes */ + int count_valid = 0, s; + for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) { + int expect_valid, valid; + if (s <= EXHAUSTIVE_TEST_ORDER) { + secp256k1_scalar s_s; + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_get_b32(sig64 + 32, &s_s); + expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && + (s_s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); + } else { + secp256k1_testrand256(sig64 + 32); + expect_valid = 0; + } + valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, &pubkeys[d - 1]); + CHECK(valid == expect_valid); + count_valid += valid; + } + /* Exactly one s value must verify, unless R is illegal. */ + CHECK(count_valid == (actual_k != -1)); + /* Don't retry other messages that result in the same challenge. */ + e_done[e] = 1; + ++e_count_done; + } + } + } + } +} + +static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) { + int d, k; + uint64_t iter = 0; + /* Loop over keys. */ + for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) { + int actual_d = d; + if (parities[d - 1]) actual_d = EXHAUSTIVE_TEST_ORDER - d; + /* Loop over nonces. */ + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; ++k) { + int e_done[EXHAUSTIVE_TEST_ORDER] = {0}; + int e_count_done = 0; + unsigned char msg32[32]; + unsigned char sig64[64]; + int actual_k = k; + if (skip_section(&iter)) continue; + if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k; + /* Generate random messages until all challenges have been tried. */ + while (e_count_done < EXHAUSTIVE_TEST_ORDER) { + secp256k1_scalar e; + secp256k1_testrand256(msg32); + secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, xonly_pubkey_bytes[d - 1]); + /* Only do work if we hit a challenge we haven't tried before. */ + if (!e_done[e]) { + secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; + unsigned char expected_s_bytes[32]; + secp256k1_scalar_get_b32(expected_s_bytes, &expected_s); + /* Invoke the real function to construct a signature. */ + CHECK(secp256k1_schnorrsig_sign(ctx, sig64, msg32, &keypairs[d - 1], secp256k1_hardened_nonce_function_smallint, &k)); + /* The first 32 bytes must match the xonly pubkey for the specified k. */ + CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0); + /* The last 32 bytes must match the expected s value. */ + CHECK(secp256k1_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0); + /* Don't retry other messages that result in the same challenge. */ + e_done[e] = 1; + ++e_count_done; + } + } + } + } +} + +static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) { + secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; + secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; + int parity[EXHAUSTIVE_TEST_ORDER - 1]; + unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; + unsigned i; + + /* Verify that all invalid_pubkey_bytes are actually invalid. */ + for (i = 0; i < NUM_INVALID_KEYS; ++i) { + secp256k1_xonly_pubkey pk; + CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i])); + } + + /* Construct keypairs and xonly-pubkeys for the entire group. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) { + secp256k1_scalar scalar_i; + unsigned char buf[32]; + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_scalar_get_b32(buf, &scalar_i); + CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); + CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1])); + CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); + } + + test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity); + test_exhaustive_schnorrsig_verify(ctx, xonly_pubkey, xonly_pubkey_bytes, parity); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorrsig/tests_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_impl.h index 88d8f56404..f522fcb320 100644 --- a/src/secp256k1/src/modules/schnorrsig/tests_impl.h +++ b/src/secp256k1/src/modules/schnorrsig/tests_impl.h @@ -15,9 +15,9 @@ void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { unsigned char nonces[2][32]; CHECK(nonce_function_bip340(nonces[0], args[0], args[1], args[2], args[3], args[4]) == 1); - secp256k1_rand_flip(args[n_flip], n_bytes); + secp256k1_testrand_flip(args[n_flip], n_bytes); CHECK(nonce_function_bip340(nonces[1], args[0], args[1], args[2], args[3], args[4]) == 1); - CHECK(memcmp(nonces[0], nonces[1], 32) != 0); + CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0); } /* Tests for the equality of two sha256 structs. This function only produces a @@ -28,7 +28,7 @@ void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) CHECK((sha1->bytes & 0x3F) == 0); CHECK(sha1->bytes == sha2->bytes); - CHECK(memcmp(sha1->s, sha2->s, sizeof(sha1->s)) == 0); + CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); } void run_nonce_function_bip340_tests(void) { @@ -59,10 +59,10 @@ void run_nonce_function_bip340_tests(void) { secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); test_sha256_eq(&sha, &sha_optimized); - secp256k1_rand256(msg); - secp256k1_rand256(key); - secp256k1_rand256(pk); - secp256k1_rand256(aux_rand); + secp256k1_testrand256(msg); + secp256k1_testrand256(key); + secp256k1_testrand256(pk); + secp256k1_testrand256(aux_rand); /* Check that a bitflip in an argument results in different nonces. */ args[0] = msg; @@ -124,10 +124,10 @@ void test_schnorrsig_api(void) { secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); - secp256k1_rand256(sk1); - secp256k1_rand256(sk2); - secp256k1_rand256(sk3); - secp256k1_rand256(msg); + secp256k1_testrand256(sk1); + secp256k1_testrand256(sk2); + secp256k1_testrand256(sk3); + secp256k1_testrand256(msg); CHECK(secp256k1_keypair_create(ctx, &keypairs[0], sk1) == 1); CHECK(secp256k1_keypair_create(ctx, &keypairs[1], sk2) == 1); CHECK(secp256k1_keypair_create(ctx, &keypairs[2], sk3) == 1); @@ -197,11 +197,11 @@ void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const un CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, aux_rand)); - CHECK(memcmp(sig, expected_sig, 64) == 0); + CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized)); CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); - CHECK(memcmp(&pk, &pk_expected, sizeof(pk)) == 0); + CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, &pk)); } @@ -675,19 +675,19 @@ void test_schnorrsig_sign(void) { unsigned char sig[64]; unsigned char zeros64[64] = { 0 }; - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1); /* Test different nonce functions */ memset(sig, 1, sizeof(sig)); CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_failing, NULL) == 0); - CHECK(memcmp(sig, zeros64, sizeof(sig)) == 0); + CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); memset(&sig, 1, sizeof(sig)); CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_0, NULL) == 0); - CHECK(memcmp(sig, zeros64, sizeof(sig)) == 0); + CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_overflowing, NULL) == 1); - CHECK(memcmp(sig, zeros64, sizeof(sig)) != 0); + CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) != 0); } #define N_SIGS 3 @@ -703,12 +703,12 @@ void test_schnorrsig_sign_verify(void) { secp256k1_xonly_pubkey pk; secp256k1_scalar s; - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); for (i = 0; i < N_SIGS; i++) { - secp256k1_rand256(msg[i]); + secp256k1_testrand256(msg[i]); CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL, NULL)); CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], &pk)); } @@ -716,19 +716,19 @@ void test_schnorrsig_sign_verify(void) { { /* Flip a few bits in the signature and in the message and check that * verify and verify_batch (TODO) fail */ - size_t sig_idx = secp256k1_rand_int(N_SIGS); - size_t byte_idx = secp256k1_rand_int(32); - unsigned char xorbyte = secp256k1_rand_int(254)+1; + size_t sig_idx = secp256k1_testrand_int(N_SIGS); + size_t byte_idx = secp256k1_testrand_int(32); + unsigned char xorbyte = secp256k1_testrand_int(254)+1; sig[sig_idx][byte_idx] ^= xorbyte; CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk)); sig[sig_idx][byte_idx] ^= xorbyte; - byte_idx = secp256k1_rand_int(32); + byte_idx = secp256k1_testrand_int(32); sig[sig_idx][32+byte_idx] ^= xorbyte; CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk)); sig[sig_idx][32+byte_idx] ^= xorbyte; - byte_idx = secp256k1_rand_int(32); + byte_idx = secp256k1_testrand_int(32); msg[sig_idx][byte_idx] ^= xorbyte; CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk)); msg[sig_idx][byte_idx] ^= xorbyte; @@ -766,7 +766,7 @@ void test_schnorrsig_taproot(void) { unsigned char sig[64]; /* Create output key */ - secp256k1_rand256(sk); + secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1); /* In actual taproot the tweak would be hash of internal_pk */ @@ -776,7 +776,7 @@ void test_schnorrsig_taproot(void) { CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1); /* Key spend */ - secp256k1_rand256(msg); + secp256k1_testrand256(msg); CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1); /* Verify key spend */ CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1); diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index 95d3e326c9..fb3fb187ce 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/src/scalar.h @@ -102,12 +102,11 @@ static void secp256k1_scalar_order_get_num(secp256k1_num *r); /** Compare two scalars. */ static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); -#ifdef USE_ENDOMORPHISM -/** Find r1 and r2 such that r1+r2*2^128 = a. */ -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); -/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); -#endif +/** Find r1 and r2 such that r1+r2*2^128 = k. */ +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); +/** Find r1 and r2 such that r1+r2*lambda = k, + * where r1 and r2 or their negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index 7f39927861..73cbd5e18a 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -912,18 +912,16 @@ static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) secp256k1_scalar_reduce_512(r, l); } -#ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - r1->d[0] = a->d[0]; - r1->d[1] = a->d[1]; +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + r1->d[0] = k->d[0]; + r1->d[1] = k->d[1]; r1->d[2] = 0; r1->d[3] = 0; - r2->d[0] = a->d[2]; - r2->d[1] = a->d[3]; + r2->d[0] = k->d[2]; + r2->d[1] = k->d[3]; r2->d[2] = 0; r2->d[3] = 0; } -#endif SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index f8c7fa7efa..6853f79ecc 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -672,26 +672,24 @@ static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) secp256k1_scalar_reduce_512(r, l); } -#ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - r1->d[0] = a->d[0]; - r1->d[1] = a->d[1]; - r1->d[2] = a->d[2]; - r1->d[3] = a->d[3]; +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + r1->d[0] = k->d[0]; + r1->d[1] = k->d[1]; + r1->d[2] = k->d[2]; + r1->d[3] = k->d[3]; r1->d[4] = 0; r1->d[5] = 0; r1->d[6] = 0; r1->d[7] = 0; - r2->d[0] = a->d[4]; - r2->d[1] = a->d[5]; - r2->d[2] = a->d[6]; - r2->d[3] = a->d[7]; + r2->d[0] = k->d[4]; + r2->d[1] = k->d[5]; + r2->d[2] = k->d[6]; + r2->d[3] = k->d[7]; r2->d[4] = 0; r2->d[5] = 0; r2->d[6] = 0; r2->d[7] = 0; } -#endif SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h index 2ec04b1ae9..fc75891818 100644 --- a/src/secp256k1/src/scalar_impl.h +++ b/src/secp256k1/src/scalar_impl.h @@ -7,6 +7,10 @@ #ifndef SECP256K1_SCALAR_IMPL_H #define SECP256K1_SCALAR_IMPL_H +#ifdef VERIFY +#include <string.h> +#endif + #include "scalar.h" #include "util.h" @@ -252,37 +256,65 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc #endif } -#ifdef USE_ENDOMORPHISM +/* These parameters are generated using sage/gen_exhaustive_groups.sage. */ #if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 13 +# define EXHAUSTIVE_TEST_LAMBDA 9 +# elif EXHAUSTIVE_TEST_ORDER == 199 +# define EXHAUSTIVE_TEST_LAMBDA 92 +# else +# error No known lambda for the specified exhaustive test group order. +# endif + /** - * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the - * full case we don't bother making k1 and k2 be small, we just want them to be + * Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the + * full case we don't bother making r1 and r2 be small, we just want them to be * nontrivial to get full test coverage for the exhaustive tests. We therefore - * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. + * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). */ -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { - *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER; - *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; + *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; } #else /** * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where - * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, - * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} + * lambda is: */ +static const secp256k1_scalar secp256k1_const_lambda = SECP256K1_SCALAR_CONST( + 0x5363AD4CUL, 0xC05C30E0UL, 0xA5261C02UL, 0x8812645AUL, + 0x122E22EAUL, 0x20816678UL, 0xDF02967CUL, 0x1B23BD72UL +); + +#ifdef VERIFY +static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k); +#endif + +/* + * Both lambda and beta are primitive cube roots of unity. That is lamba^3 == 1 mod n and + * beta^3 == 1 mod p, where n is the curve order and p is the field order. * - * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm - * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 - * and k2 have a small size. - * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: + * Futhermore, because (X^3 - 1) = (X - 1)(X^2 + X + 1), the primitive cube roots of unity are + * roots of X^2 + X + 1. Therefore lambda^2 + lamba == -1 mod n and beta^2 + beta == -1 mod p. + * (The other primitive cube roots of unity are lambda^2 and beta^2 respectively.) + * + * Let l = -1/2 + i*sqrt(3)/2, the complex root of X^2 + X + 1. We can define a ring + * homomorphism phi : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n. The kernel of phi + * is a lattice over Z[l] (considering Z[l] as a Z-module). This lattice is generated by a + * reduced basis {a1 + b1*l, a2 + b2*l} where * * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} * - * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 are small in absolute value. + * + * The algorithm computes c1 = round(b2 * k / n) and c2 = round((-b1) * k / n), and gives * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and - * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. + * compute r2 = k2 mod n, and r1 = k1 mod n = (k - r2 * lambda) mod n, avoiding the need for + * the constants a1 and a2. * * g1, g2 are precomputed constants used to replace division with a rounded multiplication * when decomposing the scalar for an endomorphism-based point multiplication. @@ -294,21 +326,21 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), * Section 4.3 (here we use a somewhat higher-precision estimate): * d = a1*b2 - b1*a2 - * g1 = round((2^272)*b2/d) - * g2 = round((2^272)*b1/d) + * g1 = round(2^384 * b2/d) + * g2 = round(2^384 * (-b1)/d) * - * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found - * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). + * (Note that d is also equal to the curve order, n, here because [a1,b1] and [a2,b2] + * can be found as outputs of the Extended Euclidean Algorithm on inputs n and lambda). * - * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). + * The function below splits k into r1 and r2, such that + * - r1 + lambda * r2 == k (mod n) + * - either r1 < 2^128 or -r1 mod n < 2^128 + * - either r2 < 2^128 or -r2 mod n < 2^128 + * + * See proof below. */ - -static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { secp256k1_scalar c1, c2; - static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST( - 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, - 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL - ); static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL @@ -318,25 +350,167 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL ); static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, - 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL + 0x3086D221UL, 0xA7D46BCDUL, 0xE86C90E4UL, 0x9284EB15UL, + 0x3DAA8A14UL, 0x71E8CA7FUL, 0xE893209AUL, 0x45DBB031UL ); static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( - 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, - 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL, + 0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL ); - VERIFY_CHECK(r1 != a); - VERIFY_CHECK(r2 != a); + VERIFY_CHECK(r1 != k); + VERIFY_CHECK(r2 != k); /* these _var calls are constant time since the shift amount is constant */ - secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); - secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); + secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384); + secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384); secp256k1_scalar_mul(&c1, &c1, &minus_b1); secp256k1_scalar_mul(&c2, &c2, &minus_b2); secp256k1_scalar_add(r2, &c1, &c2); - secp256k1_scalar_mul(r1, r2, &minus_lambda); - secp256k1_scalar_add(r1, r1, a); -} -#endif + secp256k1_scalar_mul(r1, r2, &secp256k1_const_lambda); + secp256k1_scalar_negate(r1, r1); + secp256k1_scalar_add(r1, r1, k); + +#ifdef VERIFY + secp256k1_scalar_split_lambda_verify(r1, r2, k); #endif +} + +#ifdef VERIFY +/* + * Proof for secp256k1_scalar_split_lambda's bounds. + * + * Let + * - epsilon1 = 2^256 * |g1/2^384 - b2/d| + * - epsilon2 = 2^256 * |g2/2^384 - (-b1)/d| + * - c1 = round(k*g1/2^384) + * - c2 = round(k*g2/2^384) + * + * Lemma 1: |c1 - k*b2/d| < 2^-1 + epsilon1 + * + * |c1 - k*b2/d| + * = + * |c1 - k*g1/2^384 + k*g1/2^384 - k*b2/d| + * <= {triangle inequality} + * |c1 - k*g1/2^384| + |k*g1/2^384 - k*b2/d| + * = + * |c1 - k*g1/2^384| + k*|g1/2^384 - b2/d| + * < {rounding in c1 and 0 <= k < 2^256} + * 2^-1 + 2^256 * |g1/2^384 - b2/d| + * = {definition of epsilon1} + * 2^-1 + epsilon1 + * + * Lemma 2: |c2 - k*(-b1)/d| < 2^-1 + epsilon2 + * + * |c2 - k*(-b1)/d| + * = + * |c2 - k*g2/2^384 + k*g2/2^384 - k*(-b1)/d| + * <= {triangle inequality} + * |c2 - k*g2/2^384| + |k*g2/2^384 - k*(-b1)/d| + * = + * |c2 - k*g2/2^384| + k*|g2/2^384 - (-b1)/d| + * < {rounding in c2 and 0 <= k < 2^256} + * 2^-1 + 2^256 * |g2/2^384 - (-b1)/d| + * = {definition of epsilon2} + * 2^-1 + epsilon2 + * + * Let + * - k1 = k - c1*a1 - c2*a2 + * - k2 = - c1*b1 - c2*b2 + * + * Lemma 3: |k1| < (a1 + a2 + 1)/2 < 2^128 + * + * |k1| + * = {definition of k1} + * |k - c1*a1 - c2*a2| + * = {(a1*b2 - b1*a2)/n = 1} + * |k*(a1*b2 - b1*a2)/n - c1*a1 - c2*a2| + * = + * |a1*(k*b2/n - c1) + a2*(k*(-b1)/n - c2)| + * <= {triangle inequality} + * a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2| + * < {Lemma 1 and Lemma 2} + * a1*(2^-1 + epslion1) + a2*(2^-1 + epsilon2) + * < {rounding up to an integer} + * (a1 + a2 + 1)/2 + * < {rounding up to a power of 2} + * 2^128 + * + * Lemma 4: |k2| < (-b1 + b2)/2 + 1 < 2^128 + * + * |k2| + * = {definition of k2} + * |- c1*a1 - c2*a2| + * = {(b1*b2 - b1*b2)/n = 0} + * |k*(b1*b2 - b1*b2)/n - c1*b1 - c2*b2| + * = + * |b1*(k*b2/n - c1) + b2*(k*(-b1)/n - c2)| + * <= {triangle inequality} + * (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2| + * < {Lemma 1 and Lemma 2} + * (-b1)*(2^-1 + epslion1) + b2*(2^-1 + epsilon2) + * < {rounding up to an integer} + * (-b1 + b2)/2 + 1 + * < {rounding up to a power of 2} + * 2^128 + * + * Let + * - r2 = k2 mod n + * - r1 = k - r2*lambda mod n. + * + * Notice that r1 is defined such that r1 + r2 * lambda == k (mod n). + * + * Lemma 5: r1 == k1 mod n. + * + * r1 + * == {definition of r1 and r2} + * k - k2*lambda + * == {definition of k2} + * k - (- c1*b1 - c2*b2)*lambda + * == + * k + c1*b1*lambda + c2*b2*lambda + * == {a1 + b1*lambda == 0 mod n and a2 + b2*lambda == 0 mod n} + * k - c1*a1 - c2*a2 + * == {definition of k1} + * k1 + * + * From Lemma 3, Lemma 4, Lemma 5 and the definition of r2, we can conclude that + * + * - either r1 < 2^128 or -r1 mod n < 2^128 + * - either r2 < 2^128 or -r2 mod n < 2^128. + * + * Q.E.D. + */ +static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, const secp256k1_scalar *r2, const secp256k1_scalar *k) { + secp256k1_scalar s; + unsigned char buf1[32]; + unsigned char buf2[32]; + + /* (a1 + a2 + 1)/2 is 0xa2a8918ca85bafe22016d0b917e4dd77 */ + static const unsigned char k1_bound[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa2, 0xa8, 0x91, 0x8c, 0xa8, 0x5b, 0xaf, 0xe2, 0x20, 0x16, 0xd0, 0xb9, 0x17, 0xe4, 0xdd, 0x77 + }; + + /* (-b1 + b2)/2 + 1 is 0x8a65287bd47179fb2be08846cea267ed */ + static const unsigned char k2_bound[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x65, 0x28, 0x7b, 0xd4, 0x71, 0x79, 0xfb, 0x2b, 0xe0, 0x88, 0x46, 0xce, 0xa2, 0x67, 0xed + }; + + secp256k1_scalar_mul(&s, &secp256k1_const_lambda, r2); + secp256k1_scalar_add(&s, &s, r1); + VERIFY_CHECK(secp256k1_scalar_eq(&s, k)); + + secp256k1_scalar_negate(&s, r1); + secp256k1_scalar_get_b32(buf1, r1); + secp256k1_scalar_get_b32(buf2, &s); + VERIFY_CHECK(secp256k1_memcmp_var(buf1, k1_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k1_bound, 32) < 0); + + secp256k1_scalar_negate(&s, r2); + secp256k1_scalar_get_b32(buf1, r2); + secp256k1_scalar_get_b32(buf2, &s); + VERIFY_CHECK(secp256k1_memcmp_var(buf1, k2_bound, 32) < 0 || secp256k1_memcmp_var(buf2, k2_bound, 32) < 0); +} +#endif /* VERIFY */ +#endif /* !defined(EXHAUSTIVE_TEST_ORDER) */ #endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/src/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h index b79cf1ff6c..a615ec074b 100644 --- a/src/secp256k1/src/scalar_low_impl.h +++ b/src/secp256k1/src/scalar_low_impl.h @@ -48,14 +48,17 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int } static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { - const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; int i; + int over = 0; *r = 0; for (i = 0; i < 32; i++) { - *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; + *r = (*r * 0x100) + b32[i]; + if (*r >= EXHAUSTIVE_TEST_ORDER) { + over = 1; + *r %= EXHAUSTIVE_TEST_ORDER; + } } - /* just deny overflow, it basically always happens */ - if (overflow) *overflow = 0; + if (overflow) *overflow = over; } static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { diff --git a/src/secp256k1/src/scratch_impl.h b/src/secp256k1/src/scratch_impl.h index b205620224..f381e2e322 100644 --- a/src/secp256k1/src/scratch_impl.h +++ b/src/secp256k1/src/scratch_impl.h @@ -26,7 +26,7 @@ static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* err static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) { if (scratch != NULL) { VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */ - if (memcmp(scratch->magic, "scratch", 8) != 0) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { secp256k1_callback_call(error_callback, "invalid scratch space"); return; } @@ -36,7 +36,7 @@ static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, } static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) { - if (memcmp(scratch->magic, "scratch", 8) != 0) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { secp256k1_callback_call(error_callback, "invalid scratch space"); return 0; } @@ -44,7 +44,7 @@ static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callb } static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint) { - if (memcmp(scratch->magic, "scratch", 8) != 0) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { secp256k1_callback_call(error_callback, "invalid scratch space"); return; } @@ -56,7 +56,7 @@ static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_c } static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) { - if (memcmp(scratch->magic, "scratch", 8) != 0) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { secp256k1_callback_call(error_callback, "invalid scratch space"); return 0; } @@ -81,7 +81,7 @@ static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, s } size = rounded_size; - if (memcmp(scratch->magic, "scratch", 8) != 0) { + if (secp256k1_memcmp_var(scratch->magic, "scratch", 8) != 0) { secp256k1_callback_call(error_callback, "invalid scratch space"); return NULL; } diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index eaafb3a21d..dae506d08c 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -284,6 +284,9 @@ int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pu if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { return 0; } + if (!secp256k1_ge_is_in_correct_subgroup(&Q)) { + return 0; + } secp256k1_pubkey_save(pubkey, &Q); secp256k1_ge_clear(&Q); return 1; diff --git a/src/secp256k1/src/selftest.h b/src/secp256k1/src/selftest.h index 885983aa20..0e37510c1e 100644 --- a/src/secp256k1/src/selftest.h +++ b/src/secp256k1/src/selftest.h @@ -22,7 +22,7 @@ static int secp256k1_selftest_sha256(void) { secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63); secp256k1_sha256_finalize(&hasher, out); - return memcmp(out, output32, 32) == 0; + return secp256k1_memcmp_var(out, output32, 32) == 0; } static int secp256k1_selftest(void) { diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h index bcbe15a6f1..a76003d5b8 100644 --- a/src/secp256k1/src/testrand.h +++ b/src/secp256k1/src/testrand.h @@ -14,28 +14,34 @@ /* A non-cryptographic RNG used only for test infrastructure. */ /** Seed the pseudorandom number generator for testing. */ -SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); +SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16); /** Generate a pseudorandom number in the range [0..2**32-1]. */ -static uint32_t secp256k1_rand32(void); +static uint32_t secp256k1_testrand32(void); /** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or * more. */ -static uint32_t secp256k1_rand_bits(int bits); +static uint32_t secp256k1_testrand_bits(int bits); /** Generate a pseudorandom number in the range [0..range-1]. */ -static uint32_t secp256k1_rand_int(uint32_t range); +static uint32_t secp256k1_testrand_int(uint32_t range); /** Generate a pseudorandom 32-byte array. */ -static void secp256k1_rand256(unsigned char *b32); +static void secp256k1_testrand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ -static void secp256k1_rand256_test(unsigned char *b32); +static void secp256k1_testrand256_test(unsigned char *b32); /** Generate pseudorandom bytes with long sequences of zero and one bits. */ -static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); +static void secp256k1_testrand_bytes_test(unsigned char *bytes, size_t len); /** Flip a single random bit in a byte array */ -static void secp256k1_rand_flip(unsigned char *b, size_t len); +static void secp256k1_testrand_flip(unsigned char *b, size_t len); + +/** Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL. */ +static void secp256k1_testrand_init(const char* hexseed); + +/** Print final test information. */ +static void secp256k1_testrand_finish(void); #endif /* SECP256K1_TESTRAND_H */ diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h index dfb658d9c6..3392566329 100644 --- a/src/secp256k1/src/testrand_impl.h +++ b/src/secp256k1/src/testrand_impl.h @@ -8,6 +8,7 @@ #define SECP256K1_TESTRAND_IMPL_H #include <stdint.h> +#include <stdio.h> #include <string.h> #include "testrand.h" @@ -19,11 +20,11 @@ static int secp256k1_test_rng_precomputed_used = 8; static uint64_t secp256k1_test_rng_integer; static int secp256k1_test_rng_integer_bits_left = 0; -SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { +SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16) { secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); } -SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { +SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) { if (secp256k1_test_rng_precomputed_used == 8) { secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed)); secp256k1_test_rng_precomputed_used = 0; @@ -31,10 +32,10 @@ SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; } -static uint32_t secp256k1_rand_bits(int bits) { +static uint32_t secp256k1_testrand_bits(int bits) { uint32_t ret; if (secp256k1_test_rng_integer_bits_left < bits) { - secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); + secp256k1_test_rng_integer |= (((uint64_t)secp256k1_testrand32()) << secp256k1_test_rng_integer_bits_left); secp256k1_test_rng_integer_bits_left += 32; } ret = secp256k1_test_rng_integer; @@ -44,7 +45,7 @@ static uint32_t secp256k1_rand_bits(int bits) { return ret; } -static uint32_t secp256k1_rand_int(uint32_t range) { +static uint32_t secp256k1_testrand_int(uint32_t range) { /* We want a uniform integer between 0 and range-1, inclusive. * B is the smallest number such that range <= 2**B. * two mechanisms implemented here: @@ -76,25 +77,25 @@ static uint32_t secp256k1_rand_int(uint32_t range) { mult = 1; } while(1) { - uint32_t x = secp256k1_rand_bits(bits); + uint32_t x = secp256k1_testrand_bits(bits); if (x < trange) { return (mult == 1) ? x : (x % range); } } } -static void secp256k1_rand256(unsigned char *b32) { +static void secp256k1_testrand256(unsigned char *b32) { secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); } -static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { +static void secp256k1_testrand_bytes_test(unsigned char *bytes, size_t len) { size_t bits = 0; memset(bytes, 0, len); while (bits < len * 8) { int now; uint32_t val; - now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; - val = secp256k1_rand_bits(1); + now = 1 + (secp256k1_testrand_bits(6) * secp256k1_testrand_bits(5) + 16) / 31; + val = secp256k1_testrand_bits(1); while (now > 0 && bits < len * 8) { bytes[bits / 8] |= val << (bits % 8); now--; @@ -103,12 +104,55 @@ static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { } } -static void secp256k1_rand256_test(unsigned char *b32) { - secp256k1_rand_bytes_test(b32, 32); +static void secp256k1_testrand256_test(unsigned char *b32) { + secp256k1_testrand_bytes_test(b32, 32); } -static void secp256k1_rand_flip(unsigned char *b, size_t len) { - b[secp256k1_rand_int(len)] ^= (1 << secp256k1_rand_int(8)); +static void secp256k1_testrand_flip(unsigned char *b, size_t len) { + b[secp256k1_testrand_int(len)] ^= (1 << secp256k1_testrand_int(8)); +} + +static void secp256k1_testrand_init(const char* hexseed) { + unsigned char seed16[16] = {0}; + if (hexseed && strlen(hexseed) != 0) { + int pos = 0; + while (pos < 16 && hexseed[0] != 0 && hexseed[1] != 0) { + unsigned short sh; + if ((sscanf(hexseed, "%2hx", &sh)) == 1) { + seed16[pos] = sh; + } else { + break; + } + hexseed += 2; + pos++; + } + } else { + FILE *frand = fopen("/dev/urandom", "r"); + if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) { + uint64_t t = time(NULL) * (uint64_t)1337; + fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n"); + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + if (frand) { + fclose(frand); + } + } + + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + secp256k1_testrand_seed(seed16); +} + +static void secp256k1_testrand_finish(void) { + unsigned char run32[32]; + secp256k1_testrand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); } #endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index 4780e9319b..bb4b5b4c07 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -54,7 +54,7 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { void random_field_element_test(secp256k1_fe *fe) { do { unsigned char b32[32]; - secp256k1_rand256_test(b32); + secp256k1_testrand256_test(b32); if (secp256k1_fe_set_b32(fe, b32)) { break; } @@ -63,7 +63,7 @@ void random_field_element_test(secp256k1_fe *fe) { void random_field_element_magnitude(secp256k1_fe *fe) { secp256k1_fe zero; - int n = secp256k1_rand_int(9); + int n = secp256k1_testrand_int(9); secp256k1_fe_normalize(fe); if (n == 0) { return; @@ -81,11 +81,12 @@ void random_group_element_test(secp256k1_ge *ge) { secp256k1_fe fe; do { random_field_element_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_testrand_bits(1))) { secp256k1_fe_normalize(&ge->y); break; } } while(1); + ge->infinity = 0; } void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { @@ -107,7 +108,7 @@ void random_scalar_order_test(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; - secp256k1_rand256_test(b32); + secp256k1_testrand256_test(b32); secp256k1_scalar_set_b32(num, b32, &overflow); if (overflow || secp256k1_scalar_is_zero(num)) { continue; @@ -120,7 +121,7 @@ void random_scalar_order(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; - secp256k1_rand256(b32); + secp256k1_testrand256(b32); secp256k1_scalar_set_b32(num, b32, &overflow); if (overflow || secp256k1_scalar_is_zero(num)) { continue; @@ -441,14 +442,14 @@ void run_sha256_tests(void) { secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); secp256k1_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand_int(strlen(inputs[i])); + int split = secp256k1_testrand_int(strlen(inputs[i])); secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); secp256k1_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); } } } @@ -485,14 +486,14 @@ void run_hmac_sha256_tests(void) { secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand_int(strlen(inputs[i])); + int split = secp256k1_testrand_int(strlen(inputs[i])); secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); secp256k1_hmac_sha256_finalize(&hasher, out); - CHECK(memcmp(out, outputs[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); } } } @@ -519,21 +520,21 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out1[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, out1[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out1[i], 32) != 0); + CHECK(secp256k1_memcmp_var(out, out1[i], 32) != 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); - CHECK(memcmp(out, out2[i], 32) == 0); + CHECK(secp256k1_memcmp_var(out, out2[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); } @@ -557,7 +558,7 @@ void test_rand_bits(int rand32, int bits) { /* Multiply the output of all rand calls with the odd number m, which should not change the uniformity of its distribution. */ for (i = 0; i < rounds[usebits]; i++) { - uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); + uint32_t r = (rand32 ? secp256k1_testrand32() : secp256k1_testrand_bits(bits)); CHECK((((uint64_t)r) >> bits) == 0); for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { uint32_t rm = r * mults[m]; @@ -582,7 +583,7 @@ void test_rand_int(uint32_t range, uint32_t subrange) { uint64_t x = 0; CHECK((range % subrange) == 0); for (i = 0; i < rounds; i++) { - uint32_t r = secp256k1_rand_int(range); + uint32_t r = secp256k1_testrand_int(range); CHECK(r < range); r = r % subrange; x |= (((uint64_t)1) << r); @@ -614,7 +615,7 @@ void run_rand_int(void) { #ifndef USE_NUM_NONE void random_num_negate(secp256k1_num *num) { - if (secp256k1_rand_bits(1)) { + if (secp256k1_testrand_bits(1)) { secp256k1_num_negate(num); } } @@ -658,11 +659,11 @@ void test_num_add_sub(void) { secp256k1_num n2; secp256k1_num n1p2, n2p1, n1m2, n2m1; random_num_order_test(&n1); /* n1 = R1 */ - if (secp256k1_rand_bits(1)) { + if (secp256k1_testrand_bits(1)) { random_num_negate(&n1); } random_num_order_test(&n2); /* n2 = R2 */ - if (secp256k1_rand_bits(1)) { + if (secp256k1_testrand_bits(1)) { random_num_negate(&n2); } secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ @@ -853,7 +854,7 @@ void scalar_test(void) { while (i < 256) { secp256k1_scalar t; int j; - int now = secp256k1_rand_int(15) + 1; + int now = secp256k1_testrand_int(15) + 1; if (now + i > 256) { now = 256 - i; } @@ -930,7 +931,7 @@ void scalar_test(void) { secp256k1_num rnum; secp256k1_num rnum2; unsigned char cone[1] = {0x01}; - unsigned int shift = 256 + secp256k1_rand_int(257); + unsigned int shift = 256 + secp256k1_testrand_int(257); secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); secp256k1_num_mul(&rnum, &s1num, &s2num); secp256k1_num_shift(&rnum, shift - 1); @@ -948,7 +949,7 @@ void scalar_test(void) { random_scalar_order_test(&r); for (i = 0; i < 100; ++i) { int low; - int shift = 1 + secp256k1_rand_int(15); + int shift = 1 + secp256k1_testrand_int(15); int expected = r.d[0] % (1 << shift); low = secp256k1_scalar_shr_int(&r, shift); CHECK(expected == low); @@ -996,7 +997,7 @@ void scalar_test(void) { secp256k1_scalar b; int i; /* Test add_bit. */ - int bit = secp256k1_rand_bits(8); + int bit = secp256k1_testrand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); for (i = 0; i < bit; i++) { @@ -1157,7 +1158,7 @@ void run_scalar_tests(void) { secp256k1_scalar_set_b32(&scalar, bin, &overflow); CHECK(overflow == 0); secp256k1_scalar_get_b32(bin_tmp, &scalar); - CHECK(memcmp(bin, bin_tmp, 32) == 0); + CHECK(secp256k1_memcmp_var(bin, bin_tmp, 32) == 0); /* A scalar set to all 1s should overflow. */ memset(bin, 0xFF, 32); @@ -1767,7 +1768,7 @@ void run_scalar_tests(void) { void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { - secp256k1_rand256(bin); + secp256k1_testrand256(bin); if (secp256k1_fe_set_b32(x, bin)) { return; } @@ -1777,7 +1778,7 @@ void random_fe(secp256k1_fe *x) { void random_fe_test(secp256k1_fe *x) { unsigned char bin[32]; do { - secp256k1_rand256_test(bin); + secp256k1_testrand256_test(bin); if (secp256k1_fe_set_b32(x, bin)) { return; } @@ -1845,18 +1846,18 @@ void run_field_convert(void) { CHECK(secp256k1_fe_equal_var(&fe, &fe2)); /* Check conversion from fe. */ secp256k1_fe_get_b32(b322, &fe); - CHECK(memcmp(b322, b32, 32) == 0); + CHECK(secp256k1_memcmp_var(b322, b32, 32) == 0); secp256k1_fe_to_storage(&fes2, &fe); - CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); + CHECK(secp256k1_memcmp_var(&fes2, &fes, sizeof(fes)) == 0); } -int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) { +int fe_secp256k1_memcmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe t = *b; #ifdef VERIFY t.magnitude = a->magnitude; t.normalized = a->normalized; #endif - return memcmp(a, &t, sizeof(secp256k1_fe)); + return secp256k1_memcmp_var(a, &t, sizeof(secp256k1_fe)); } void run_field_misc(void) { @@ -1882,13 +1883,13 @@ void run_field_misc(void) { CHECK(x.normalized && x.magnitude == 1); #endif secp256k1_fe_cmov(&x, &x, 1); - CHECK(fe_memcmp(&x, &z) != 0); - CHECK(fe_memcmp(&x, &q) == 0); + CHECK(fe_secp256k1_memcmp_var(&x, &z) != 0); + CHECK(fe_secp256k1_memcmp_var(&x, &q) == 0); secp256k1_fe_cmov(&q, &z, 1); #ifdef VERIFY CHECK(!q.normalized && q.magnitude == z.magnitude); #endif - CHECK(fe_memcmp(&q, &z) == 0); + CHECK(fe_secp256k1_memcmp_var(&q, &z) == 0); secp256k1_fe_normalize_var(&x); secp256k1_fe_normalize_var(&z); CHECK(!secp256k1_fe_equal_var(&x, &z)); @@ -1912,9 +1913,9 @@ void run_field_misc(void) { secp256k1_fe_to_storage(&zs, &z); secp256k1_fe_storage_cmov(&zs, &xs, 0); secp256k1_fe_storage_cmov(&zs, &zs, 1); - CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); + CHECK(secp256k1_memcmp_var(&xs, &zs, sizeof(xs)) != 0); secp256k1_fe_storage_cmov(&ys, &xs, 1); - CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); + CHECK(secp256k1_memcmp_var(&xs, &ys, sizeof(xs)) == 0); secp256k1_fe_from_storage(&x, &xs); secp256k1_fe_from_storage(&y, &ys); secp256k1_fe_from_storage(&z, &zs); @@ -1970,7 +1971,7 @@ void run_field_inv_all_var(void) { secp256k1_fe_inv_all_var(xi, x, 0); for (i = 0; i < count; i++) { size_t j; - size_t len = secp256k1_rand_int(15) + 1; + size_t len = secp256k1_testrand_int(15) + 1; for (j = 0; j < len; j++) { random_fe_non_zero(&x[j]); } @@ -2101,17 +2102,12 @@ void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { void test_ge(void) { int i, i1; -#ifdef USE_ENDOMORPHISM int runs = 6; -#else - int runs = 4; -#endif - /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). - * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. - * All magnitudes are randomized. - * All 17*17 combinations of points are added to each other, using all applicable methods. - * - * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. + /* 25 points are used: + * - infinity + * - for each of four random points p1 p2 p3 p4, we add the point, its + * negation, and then those two again but with randomized Z coordinate. + * - The same is then done for lambda*p1 and lambda^2*p1. */ secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); @@ -2126,14 +2122,12 @@ void test_ge(void) { int j; secp256k1_ge g; random_group_element_test(&g); -#ifdef USE_ENDOMORPHISM if (i >= runs - 2) { secp256k1_ge_mul_lambda(&g, &ge[1]); } if (i >= runs - 1) { secp256k1_ge_mul_lambda(&g, &g); } -#endif ge[1 + 4 * i] = g; ge[2 + 4 * i] = g; secp256k1_ge_neg(&ge[3 + 4 * i], &g); @@ -2262,7 +2256,7 @@ void test_ge(void) { gej_shuffled[i] = gej[i]; } for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + secp256k1_rand_int(4 * runs + 1 - i); + int swap = i + secp256k1_testrand_int(4 * runs + 1 - i); if (swap != i) { secp256k1_gej t = gej_shuffled[i]; gej_shuffled[i] = gej_shuffled[swap]; @@ -2448,7 +2442,7 @@ void test_ec_combine(void) { secp256k1_ge_set_gej(&Q, &Qj); secp256k1_pubkey_save(&sd, &Q); CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1); - CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); + CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); } } @@ -2614,7 +2608,6 @@ void test_point_times_order(const secp256k1_gej *point) { secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ secp256k1_gej_add_var(&res1, &res1, &res2, NULL); CHECK(secp256k1_gej_is_infinity(&res1)); - CHECK(secp256k1_gej_is_valid_var(&res1) == 0); secp256k1_ge_set_gej(&res3, &res1); CHECK(secp256k1_ge_is_infinity(&res3)); CHECK(secp256k1_ge_is_valid_var(&res3) == 0); @@ -2633,6 +2626,87 @@ void test_point_times_order(const secp256k1_gej *point) { ge_equals_ge(&res3, &secp256k1_ge_const_g); } +/* These scalars reach large (in absolute value) outputs when fed to secp256k1_scalar_split_lambda. + * + * They are computed as: + * - For a in [-2, -1, 0, 1, 2]: + * - For b in [-3, -1, 1, 3]: + * - Output (a*LAMBDA + (ORDER+b)/2) % ORDER + */ +static const secp256k1_scalar scalars_near_split_bounds[20] = { + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fc), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fd), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6fe), + SECP256K1_SCALAR_CONST(0xd938a566, 0x7f479e3e, 0xb5b3c7fa, 0xefdb3749, 0x3aa0585c, 0xc5ea2367, 0xe1b660db, 0x0209e6ff), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632d), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632e), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf7632f), + SECP256K1_SCALAR_CONST(0x2c9c52b3, 0x3fa3cf1f, 0x5ad9e3fd, 0x77ed9ba5, 0xb294b893, 0x3722e9a5, 0x00e698ca, 0x4cf76330), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b209f), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a0), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a1), + SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xd576e735, 0x57a4501d, 0xdfe92f46, 0x681b20a2), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede11), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede12), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede13), + SECP256K1_SCALAR_CONST(0xd363ad4c, 0xc05c30e0, 0xa5261c02, 0x88126459, 0xf85915d7, 0x7825b696, 0xbeebc5c2, 0x833ede14), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a42), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a43), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a44), + SECP256K1_SCALAR_CONST(0x26c75a99, 0x80b861c1, 0x4a4c3805, 0x1024c8b4, 0x704d760e, 0xe95e7cd3, 0xde1bfdb1, 0xce2c5a45) +}; + +void test_ecmult_target(const secp256k1_scalar* target, int mode) { + /* Mode: 0=ecmult_gen, 1=ecmult, 2=ecmult_const */ + secp256k1_scalar n1, n2; + secp256k1_ge p; + secp256k1_gej pj, p1j, p2j, ptj; + static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + + /* Generate random n1,n2 such that n1+n2 = -target. */ + random_scalar_order_test(&n1); + secp256k1_scalar_add(&n2, &n1, target); + secp256k1_scalar_negate(&n2, &n2); + + /* Generate a random input point. */ + if (mode != 0) { + random_group_element_test(&p); + secp256k1_gej_set_ge(&pj, &p); + } + + /* EC multiplications */ + if (mode == 0) { + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &p1j, &n1); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &p2j, &n2); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &ptj, target); + } else if (mode == 1) { + secp256k1_ecmult(&ctx->ecmult_ctx, &p1j, &pj, &n1, &zero); + secp256k1_ecmult(&ctx->ecmult_ctx, &p2j, &pj, &n2, &zero); + secp256k1_ecmult(&ctx->ecmult_ctx, &ptj, &pj, target, &zero); + } else { + secp256k1_ecmult_const(&p1j, &p, &n1, 256); + secp256k1_ecmult_const(&p2j, &p, &n2, 256); + secp256k1_ecmult_const(&ptj, &p, target, 256); + } + + /* Add them all up: n1*P + n2*P + target*P = (n1+n2+target)*P = (n1+n1-n1-n2)*P = 0. */ + secp256k1_gej_add_var(&ptj, &ptj, &p1j, NULL); + secp256k1_gej_add_var(&ptj, &ptj, &p2j, NULL); + CHECK(secp256k1_gej_is_infinity(&ptj)); +} + +void run_ecmult_near_split_bound(void) { + int i; + unsigned j; + for (i = 0; i < 4*count; ++i) { + for (j = 0; j < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++j) { + test_ecmult_target(&scalars_near_split_bounds[j], 0); + test_ecmult_target(&scalars_near_split_bounds[j], 1); + test_ecmult_target(&scalars_near_split_bounds[j], 2); + } + } +} + void run_point_times_order(void) { int i; secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); @@ -2646,7 +2720,6 @@ void run_point_times_order(void) { secp256k1_gej j; CHECK(secp256k1_ge_is_valid_var(&p)); secp256k1_gej_set_ge(&j, &p); - CHECK(secp256k1_gej_is_valid_var(&j)); test_point_times_order(&j); } secp256k1_fe_sqr(&x, &x); @@ -3042,12 +3115,10 @@ void test_secp256k1_pippenger_bucket_window_inv(void) { CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0); for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) { -#ifdef USE_ENDOMORPHISM /* Bucket_window of 8 is not used with endo */ if (i == 8) { continue; } -#endif CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)) == i); if (i != PIPPENGER_MAX_BUCKET_WINDOW) { CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)+1) > i); @@ -3060,7 +3131,7 @@ void test_secp256k1_pippenger_bucket_window_inv(void) { * for a given scratch space. */ void test_ecmult_multi_pippenger_max_points(void) { - size_t scratch_size = secp256k1_rand_int(256); + size_t scratch_size = secp256k1_testrand_int(256); size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12); secp256k1_scratch *scratch; size_t n_points_supported; @@ -3290,13 +3361,10 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&shift, 1 << w); - /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ -#ifdef USE_ENDOMORPHISM for (i = 0; i < 16; ++i) { secp256k1_scalar_shr_int(&num, 8); } bits = 128; -#endif skew = secp256k1_wnaf_const(wnaf, &num, w, bits); for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) { @@ -3331,12 +3399,9 @@ void test_fixed_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&shift, 1 << w); - /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ -#ifdef USE_ENDOMORPHISM for (i = 0; i < 16; ++i) { secp256k1_scalar_shr_int(&num, 8); } -#endif skew = secp256k1_wnaf_fixed(wnaf, &num, w); for (i = WNAF_SIZE(w)-1; i >= 0; --i) { @@ -3520,7 +3585,7 @@ void test_ecmult_gen_blind(void) { secp256k1_ge pge; random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); - secp256k1_rand256(seed32); + secp256k1_testrand256(seed32); b = ctx->ecmult_gen_ctx.blind; i = ctx->ecmult_gen_ctx.initial; secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); @@ -3552,16 +3617,18 @@ void run_ecmult_gen_blind(void) { } } -#ifdef USE_ENDOMORPHISM /***** ENDOMORPHISH TESTS *****/ -void test_scalar_split(void) { - secp256k1_scalar full; - secp256k1_scalar s1, slam; +void test_scalar_split(const secp256k1_scalar* full) { + secp256k1_scalar s, s1, slam; const unsigned char zero[32] = {0}; unsigned char tmp[32]; - random_scalar_order_test(&full); - secp256k1_scalar_split_lambda(&s1, &slam, &full); + secp256k1_scalar_split_lambda(&s1, &slam, full); + + /* check slam*lambda + s1 == full */ + secp256k1_scalar_mul(&s, &secp256k1_const_lambda, &slam); + secp256k1_scalar_add(&s, &s, &s1); + CHECK(secp256k1_scalar_eq(&s, full)); /* check that both are <= 128 bits in size */ if (secp256k1_scalar_is_high(&s1)) { @@ -3572,15 +3639,32 @@ void test_scalar_split(void) { } secp256k1_scalar_get_b32(tmp, &s1); - CHECK(memcmp(zero, tmp, 16) == 0); + CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); secp256k1_scalar_get_b32(tmp, &slam); - CHECK(memcmp(zero, tmp, 16) == 0); + CHECK(secp256k1_memcmp_var(zero, tmp, 16) == 0); } + void run_endomorphism_tests(void) { - test_scalar_split(); + unsigned i; + static secp256k1_scalar s; + test_scalar_split(&secp256k1_scalar_zero); + test_scalar_split(&secp256k1_scalar_one); + secp256k1_scalar_negate(&s,&secp256k1_scalar_one); + test_scalar_split(&s); + test_scalar_split(&secp256k1_const_lambda); + secp256k1_scalar_add(&s, &secp256k1_const_lambda, &secp256k1_scalar_one); + test_scalar_split(&s); + + for (i = 0; i < 100U * count; ++i) { + secp256k1_scalar full; + random_scalar_order_test(&full); + test_scalar_split(&full); + } + for (i = 0; i < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++i) { + test_scalar_split(&scalars_near_split_bounds[i]); + } } -#endif void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { unsigned char pubkeyc[65]; @@ -3622,7 +3706,7 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); VG_CHECK(pubkeyo, outl); CHECK(outl == 33); - CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK(secp256k1_memcmp_var(&pubkeyo[1], &pubkeyc[1], 32) == 0); CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); if (ypass) { /* This test isn't always done because we decode with alternative signs, so the y won't match. */ @@ -3638,7 +3722,7 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali VG_CHECK(pubkeyo, outl); CHECK(outl == 65); CHECK(pubkeyo[0] == 4); - CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0); } CHECK(ecount == 0); } else { @@ -4007,7 +4091,7 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* Maximum value is too large, reject. */ memset(ctmp, 255, 32); CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); @@ -4015,7 +4099,7 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* Zero is too small, reject. */ memset(ctmp, 0, 32); CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); @@ -4023,7 +4107,7 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* One must be accepted. */ ctmp[31] = 0x01; CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); @@ -4031,7 +4115,7 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); pubkey_one = pubkey; /* Group order + 1 is too large, reject. */ memcpy(ctmp, orderc, 32); @@ -4041,7 +4125,7 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* -1 must be accepted. */ ctmp[31] = 0x40; CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); @@ -4049,20 +4133,20 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); VG_CHECK(&pubkey, sizeof(pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); pubkey_negone = pubkey; /* Tweak of zero leaves the value unchanged. */ memset(ctmp2, 0, 32); CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 1); - CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + CHECK(secp256k1_memcmp_var(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); memcpy(&pubkey2, &pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Multiply tweak of zero zeroizes the output. */ CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing seckey, the seckey is zeroized. */ @@ -4072,29 +4156,29 @@ void run_eckey_edge_case_test(void) { CHECK(secp256k1_ec_seckey_verify(ctx, ctmp2) == 1); CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, ctmp2) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, ctmp2) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); /* If seckey_tweak_add or seckey_tweak_mul are called with an overflowing tweak, the seckey is zeroized. */ memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp, orderc) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; CHECK(secp256k1_ec_seckey_tweak_mul(ctx, ctmp, orderc) == 0); - CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp, 32) == 0); memcpy(ctmp, orderc, 32); ctmp[31] = 0x40; /* If pubkey_tweak_add or pubkey_tweak_mul are called with an overflowing tweak, the pubkey is zeroized. */ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); /* If the resulting key in secp256k1_ec_seckey_tweak_add and * secp256k1_ec_pubkey_tweak_add is 0 the functions fail and in the latter @@ -4104,25 +4188,25 @@ void run_eckey_edge_case_test(void) { memset(ctmp2, 0, 32); ctmp2[31] = 1; CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 0); - CHECK(memcmp(zeros, ctmp2, 32) == 0); + CHECK(secp256k1_memcmp_var(zeros, ctmp2, 32) == 0); ctmp2[31] = 1; CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); /* Tweak computation wraps and results in a key of 1. */ ctmp2[31] = 2; CHECK(secp256k1_ec_seckey_tweak_add(ctx, ctmp2, ctmp) == 1); - CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + CHECK(secp256k1_memcmp_var(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); ctmp2[31] = 2; CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); ctmp2[31] = 1; CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Tweak mul * 2 = 1+1. */ CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); ctmp2[31] = 2; CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); /* Test argument errors. */ ecount = 0; secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); @@ -4131,12 +4215,12 @@ void run_eckey_edge_case_test(void) { memset(&pubkey, 0, 32); CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); CHECK(ecount == 1); - CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); memset(&pubkey2, 0, 32); CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); CHECK(ecount == 2); - CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0); /* Plain argument errors. */ ecount = 0; CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); @@ -4176,7 +4260,7 @@ void run_eckey_edge_case_test(void) { memset(&pubkey, 1, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); CHECK(ecount == 2); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* secp256k1_ec_pubkey_combine tests. */ ecount = 0; pubkeys[0] = &pubkey_one; @@ -4187,28 +4271,28 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 1); CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 2); memset(&pubkey, 255, sizeof(secp256k1_pubkey)); VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 3); pubkeys[0] = &pubkey_negone; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); CHECK(ecount == 3); len = 33; CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); - CHECK(memcmp(ctmp, ctmp2, 33) == 0); + CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); /* Result is infinity. */ pubkeys[0] = &pubkey_one; pubkeys[1] = &pubkey_negone; @@ -4216,7 +4300,7 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); CHECK(ecount == 3); /* Passes through infinity but comes out one. */ pubkeys[2] = &pubkey_one; @@ -4224,19 +4308,19 @@ void run_eckey_edge_case_test(void) { VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); CHECK(ecount == 3); len = 33; CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); - CHECK(memcmp(ctmp, ctmp2, 33) == 0); + CHECK(secp256k1_memcmp_var(ctmp, ctmp2, 33) == 0); /* Adds to two. */ pubkeys[1] = &pubkey_one; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); CHECK(ecount == 3); secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } @@ -4250,21 +4334,21 @@ void run_eckey_negate_test(void) { /* Verify negation changes the key and changes it back */ CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1); - CHECK(memcmp(seckey, seckey_tmp, 32) != 0); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) != 0); CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1); - CHECK(memcmp(seckey, seckey_tmp, 32) == 0); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); /* Check that privkey alias gives same result */ CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 1); CHECK(secp256k1_ec_privkey_negate(ctx, seckey_tmp) == 1); - CHECK(memcmp(seckey, seckey_tmp, 32) == 0); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); /* Negating all 0s fails */ memset(seckey, 0, 32); memset(seckey_tmp, 0, 32); CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0); /* Check that seckey is not modified */ - CHECK(memcmp(seckey, seckey_tmp, 32) == 0); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); /* Negating an overflowing seckey fails and the seckey is zeroed. In this * test, the seckey has 16 random bytes to ensure that ec_seckey_negate @@ -4273,7 +4357,7 @@ void run_eckey_negate_test(void) { memset(seckey, 0xFF, 16); memset(seckey_tmp, 0, 32); CHECK(secp256k1_ec_seckey_negate(ctx, seckey) == 0); - CHECK(memcmp(seckey, seckey_tmp, 32) == 0); + CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); } void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { @@ -4295,7 +4379,7 @@ void test_ecdsa_sign_verify(void) { random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_rand_bits(1); + getrec = secp256k1_testrand_bits(1); random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); if (getrec) { CHECK(recid >= 0 && recid < 4); @@ -4362,7 +4446,7 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char int is_empty_signature(const secp256k1_ecdsa_signature *sig) { static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; - return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; + return secp256k1_memcmp_var(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; } void test_ecdsa_end_to_end(void) { @@ -4395,31 +4479,31 @@ void test_ecdsa_end_to_end(void) { CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); /* Verify exporting and importing public key. */ - CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_testrand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); memset(&pubkey, 0, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); /* Verify negation changes the key and changes it back */ memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); - CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); + CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); - CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); /* Verify private key import and export. */ - CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); + CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_testrand_bits(1) == 1)); CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); - CHECK(memcmp(privkey, privkey2, 32) == 0); + CHECK(secp256k1_memcmp_var(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (secp256k1_rand_int(3) == 0) { + if (secp256k1_testrand_int(3) == 0) { int ret1; int ret2; int ret3; unsigned char rnd[32]; unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; - secp256k1_rand256_test(rnd); + secp256k1_testrand256_test(rnd); memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_add(ctx, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); @@ -4430,20 +4514,20 @@ void test_ecdsa_end_to_end(void) { if (ret1 == 0) { return; } - CHECK(memcmp(privkey, privkey_tmp, 32) == 0); + CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Optionally tweak the keys using multiplication. */ - if (secp256k1_rand_int(3) == 0) { + if (secp256k1_testrand_int(3) == 0) { int ret1; int ret2; int ret3; unsigned char rnd[32]; unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; - secp256k1_rand256_test(rnd); + secp256k1_testrand256_test(rnd); memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_mul(ctx, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); @@ -4454,9 +4538,9 @@ void test_ecdsa_end_to_end(void) { if (ret1 == 0) { return; } - CHECK(memcmp(privkey, privkey_tmp, 32) == 0); + CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); - CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ @@ -4468,13 +4552,13 @@ void test_ecdsa_end_to_end(void) { extra[31] = 0; extra[0] = 1; CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); - CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); - CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); - CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(secp256k1_memcmp_var(&signature[2], &signature[3], sizeof(signature[0])) != 0); /* Verify. */ CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); @@ -4495,7 +4579,7 @@ void test_ecdsa_end_to_end(void) { secp256k1_ecdsa_signature_save(&signature[5], &r, &s); CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); - CHECK(memcmp(&signature[5], &signature[0], 64) == 0); + CHECK(secp256k1_memcmp_var(&signature[5], &signature[0], 64) == 0); /* Serialize/parse DER and verify again */ CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); @@ -4505,7 +4589,7 @@ void test_ecdsa_end_to_end(void) { /* Serialize/destroy/parse DER and verify again. */ siglen = 74; CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); - sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); + sig[secp256k1_testrand_int(siglen)] += 1 + secp256k1_testrand_int(255); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); } @@ -4515,23 +4599,23 @@ void test_random_pubkeys(void) { secp256k1_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; - if (secp256k1_rand_bits(2) == 0) { - len = secp256k1_rand_bits(6); + size_t len = secp256k1_testrand_bits(2) == 0 ? 65 : 33; + if (secp256k1_testrand_bits(2) == 0) { + len = secp256k1_testrand_bits(6); } if (len == 65) { - in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); + in[0] = secp256k1_testrand_bits(1) ? 4 : (secp256k1_testrand_bits(1) ? 6 : 7); } else { - in[0] = secp256k1_rand_bits(1) ? 2 : 3; + in[0] = secp256k1_testrand_bits(1) ? 2 : 3; } - if (secp256k1_rand_bits(3) == 0) { - in[0] = secp256k1_rand_bits(8); + if (secp256k1_testrand_bits(3) == 0) { + in[0] = secp256k1_testrand_bits(8); } if (len > 1) { - secp256k1_rand256(&in[1]); + secp256k1_testrand256(&in[1]); } if (len > 33) { - secp256k1_rand256(&in[33]); + secp256k1_testrand256(&in[33]); } if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { unsigned char out[65]; @@ -4542,7 +4626,7 @@ void test_random_pubkeys(void) { /* If the pubkey can be parsed, it should round-trip... */ CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); CHECK(size == len); - CHECK(memcmp(&in[1], &out[1], len-1) == 0); + CHECK(secp256k1_memcmp_var(&in[1], &out[1], len-1) == 0); /* ... except for the type of hybrid inputs. */ if ((in[0] != 6) && (in[0] != 7)) { CHECK(in[0] == out[0]); @@ -4553,7 +4637,7 @@ void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); ge_equals_ge(&elem,&elem2); /* Check that the X9.62 hybrid type is checked. */ - in[0] = secp256k1_rand_bits(1) ? 6 : 7; + in[0] = secp256k1_testrand_bits(1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { if (in[0] == firstb + 4) { @@ -4565,7 +4649,7 @@ void test_random_pubkeys(void) { if (res) { ge_equals_ge(&elem,&elem2); CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); - CHECK(memcmp(&in[1], &out[1], 64) == 0); + CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0); } } } @@ -4621,21 +4705,21 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); if (parsed_der) { ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; - valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + valid_der = (secp256k1_memcmp_var(compact_der, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der + 32, zeroes, 32) != 0); } if (valid_der) { ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; - roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + roundtrips_der = (len_der == siglen) && secp256k1_memcmp_var(roundtrip_der, sig, siglen) == 0; } parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); if (parsed_der_lax) { ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; - valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + valid_der_lax = (secp256k1_memcmp_var(compact_der_lax, zeroes, 32) != 0) && (secp256k1_memcmp_var(compact_der_lax + 32, zeroes, 32) != 0); } if (valid_der_lax) { ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; - roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + roundtrips_der_lax = (len_der_lax == siglen) && secp256k1_memcmp_var(roundtrip_der_lax, sig, siglen) == 0; } if (certainly_der) { @@ -4651,7 +4735,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ if (valid_der) { ret |= (!roundtrips_der_lax) << 12; ret |= (len_der != len_der_lax) << 13; - ret |= ((len_der != len_der_lax) || (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; + ret |= ((len_der != len_der_lax) || (secp256k1_memcmp_var(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14; } ret |= (roundtrips_der != roundtrips_der_lax) << 15; if (parsed_der) { @@ -4668,19 +4752,19 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ if (valid_openssl) { unsigned char tmp[32] = {0}; BN_bn2bin(r, tmp + 32 - BN_num_bytes(r)); - valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + valid_openssl = secp256k1_memcmp_var(tmp, max_scalar, 32) < 0; } if (valid_openssl) { unsigned char tmp[32] = {0}; BN_bn2bin(s, tmp + 32 - BN_num_bytes(s)); - valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + valid_openssl = secp256k1_memcmp_var(tmp, max_scalar, 32) < 0; } } len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); if (len_openssl <= 2048) { unsigned char *ptr = roundtrip_openssl; CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); - roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); + roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (secp256k1_memcmp_var(roundtrip_openssl, sig, siglen) == 0); } else { len_openssl = 0; } @@ -4692,7 +4776,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_ ret |= (roundtrips_der != roundtrips_openssl) << 7; if (roundtrips_openssl) { ret |= (len_der != (size_t)len_openssl) << 8; - ret |= ((len_der != (size_t)len_openssl) || (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0)) << 9; + ret |= ((len_der != (size_t)len_openssl) || (secp256k1_memcmp_var(roundtrip_der, roundtrip_openssl, len_der) != 0)) << 9; } #endif return ret; @@ -4712,27 +4796,27 @@ static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { static void damage_array(unsigned char *sig, size_t *len) { int pos; - int action = secp256k1_rand_bits(3); + int action = secp256k1_testrand_bits(3); if (action < 1 && *len > 3) { /* Delete a byte. */ - pos = secp256k1_rand_int(*len); + pos = secp256k1_testrand_int(*len); memmove(sig + pos, sig + pos + 1, *len - pos - 1); (*len)--; return; } else if (action < 2 && *len < 2048) { /* Insert a byte. */ - pos = secp256k1_rand_int(1 + *len); + pos = secp256k1_testrand_int(1 + *len); memmove(sig + pos + 1, sig + pos, *len - pos); - sig[pos] = secp256k1_rand_bits(8); + sig[pos] = secp256k1_testrand_bits(8); (*len)++; return; } else if (action < 4) { /* Modify a byte. */ - sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); + sig[secp256k1_testrand_int(*len)] += 1 + secp256k1_testrand_int(255); return; } else { /* action < 8 */ /* Modify a bit. */ - sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); + sig[secp256k1_testrand_int(*len)] ^= 1 << secp256k1_testrand_bits(3); return; } } @@ -4745,23 +4829,23 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly int n; *len = 0; - der = secp256k1_rand_bits(2) == 0; + der = secp256k1_testrand_bits(2) == 0; *certainly_der = der; *certainly_not_der = 0; - indet = der ? 0 : secp256k1_rand_int(10) == 0; + indet = der ? 0 : secp256k1_testrand_int(10) == 0; for (n = 0; n < 2; n++) { /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ - nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); + nlow[n] = der ? 1 : (secp256k1_testrand_bits(3) != 0); /* The length of the number in bytes (the first byte of which will always be nonzero) */ - nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; + nlen[n] = nlow[n] ? secp256k1_testrand_int(33) : 32 + secp256k1_testrand_int(200) * secp256k1_testrand_int(8) / 8; CHECK(nlen[n] <= 232); /* The top bit of the number. */ - nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_testrand_bits(1)); /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ - nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_testrand_bits(7) : 1 + secp256k1_testrand_int(127)); /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ - nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8); + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_testrand_int(3) : secp256k1_testrand_int(300 - nlen[n]) * secp256k1_testrand_int(8) / 8); if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { *certainly_not_der = 1; } @@ -4770,7 +4854,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); if (!der) { /* nlenlen[n] max 127 bytes */ - int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + int add = secp256k1_testrand_int(127 - nlenlen[n]) * secp256k1_testrand_int(16) * secp256k1_testrand_int(16) / 256; nlenlen[n] += add; if (add != 0) { *certainly_not_der = 1; @@ -4784,7 +4868,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 856); /* The length of the garbage inside the tuple. */ - elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; + elen = (der || indet) ? 0 : secp256k1_testrand_int(980 - tlen) * secp256k1_testrand_int(8) / 8; if (elen != 0) { *certainly_not_der = 1; } @@ -4792,7 +4876,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen <= 980); /* The length of the garbage after the end of the tuple. */ - glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; + glen = der ? 0 : secp256k1_testrand_int(990 - tlen) * secp256k1_testrand_int(8) / 8; if (glen != 0) { *certainly_not_der = 1; } @@ -4807,7 +4891,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly } else { int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); if (!der) { - int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + int add = secp256k1_testrand_int(127 - tlenlen) * secp256k1_testrand_int(16) * secp256k1_testrand_int(16) / 256; tlenlen += add; if (add != 0) { *certainly_not_der = 1; @@ -4858,13 +4942,13 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly nlen[n]--; } /* Generate remaining random bytes of number */ - secp256k1_rand_bytes_test(sig + *len, nlen[n]); + secp256k1_testrand_bytes_test(sig + *len, nlen[n]); *len += nlen[n]; nlen[n] = 0; } /* Generate random garbage inside tuple. */ - secp256k1_rand_bytes_test(sig + *len, elen); + secp256k1_testrand_bytes_test(sig + *len, elen); *len += elen; /* Generate end-of-contents bytes. */ @@ -4876,7 +4960,7 @@ static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly CHECK(tlen + glen <= 1121); /* Generate random garbage outside tuple. */ - secp256k1_rand_bytes_test(sig + *len, glen); + secp256k1_testrand_bytes_test(sig + *len, glen); *len += glen; tlen += glen; CHECK(tlen <= 1121); @@ -5208,11 +5292,11 @@ void test_ecdsa_edge_cases(void) { CHECK(!is_empty_signature(&sig)); CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); CHECK(!is_empty_signature(&sig2)); - CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function is deterministic. */ CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function changes output with different messages. */ for(i = 0; i < 256; i++) { int j; @@ -5259,12 +5343,12 @@ void test_ecdsa_edge_cases(void) { VG_CHECK(nonce3,32); CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); VG_CHECK(nonce4,32); - CHECK(memcmp(nonce, nonce2, 32) != 0); - CHECK(memcmp(nonce, nonce3, 32) != 0); - CHECK(memcmp(nonce, nonce4, 32) != 0); - CHECK(memcmp(nonce2, nonce3, 32) != 0); - CHECK(memcmp(nonce2, nonce4, 32) != 0); - CHECK(memcmp(nonce3, nonce4, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce, nonce3, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce, nonce4, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce2, nonce3, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce2, nonce4, 32) != 0); + CHECK(secp256k1_memcmp_var(nonce3, nonce4, 32) != 0); } @@ -5293,7 +5377,7 @@ EC_KEY *get_openssl_key(const unsigned char *key32) { unsigned char privkey[300]; size_t privkeylen; const unsigned char* pbegin = privkey; - int compr = secp256k1_rand_bits(1); + int compr = secp256k1_testrand_bits(1); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); @@ -5314,7 +5398,7 @@ void test_ecdsa_openssl(void) { unsigned char message[32]; unsigned char signature[80]; unsigned char key32[32]; - secp256k1_rand256_test(message); + secp256k1_testrand256_test(message); secp256k1_scalar_set_b32(&msg, message, NULL); random_scalar_order_test(&key); secp256k1_scalar_get_b32(key32, &key); @@ -5367,12 +5451,12 @@ void run_memczero_test(void) { /* memczero(..., ..., 0) is a noop. */ memcpy(buf2, buf1, sizeof(buf1)); memczero(buf1, sizeof(buf1), 0); - CHECK(memcmp(buf1, buf2, sizeof(buf1)) == 0); + CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); /* memczero(..., ..., 1) zeros the buffer. */ memset(buf2, 0, sizeof(buf2)); memczero(buf1, sizeof(buf1) , 1); - CHECK(memcmp(buf1, buf2, sizeof(buf1)) == 0); + CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0); } void int_cmov_test(void) { @@ -5411,23 +5495,23 @@ void fe_cmov_test(void) { secp256k1_fe a = zero; secp256k1_fe_cmov(&r, &a, 0); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); r = zero; a = max; secp256k1_fe_cmov(&r, &a, 1); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); a = zero; secp256k1_fe_cmov(&r, &a, 1); - CHECK(memcmp(&r, &zero, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); a = one; secp256k1_fe_cmov(&r, &a, 1); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); r = one; a = zero; secp256k1_fe_cmov(&r, &a, 0); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } void fe_storage_cmov_test(void) { @@ -5441,23 +5525,23 @@ void fe_storage_cmov_test(void) { secp256k1_fe_storage a = zero; secp256k1_fe_storage_cmov(&r, &a, 0); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); r = zero; a = max; secp256k1_fe_storage_cmov(&r, &a, 1); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); a = zero; secp256k1_fe_storage_cmov(&r, &a, 1); - CHECK(memcmp(&r, &zero, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); a = one; secp256k1_fe_storage_cmov(&r, &a, 1); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); r = one; a = zero; secp256k1_fe_storage_cmov(&r, &a, 0); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } void scalar_cmov_test(void) { @@ -5471,23 +5555,23 @@ void scalar_cmov_test(void) { secp256k1_scalar a = zero; secp256k1_scalar_cmov(&r, &a, 0); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); r = zero; a = max; secp256k1_scalar_cmov(&r, &a, 1); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); a = zero; secp256k1_scalar_cmov(&r, &a, 1); - CHECK(memcmp(&r, &zero, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); a = one; secp256k1_scalar_cmov(&r, &a, 1); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); r = one; a = zero; secp256k1_scalar_cmov(&r, &a, 0); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } void ge_storage_cmov_test(void) { @@ -5503,23 +5587,23 @@ void ge_storage_cmov_test(void) { secp256k1_ge_storage a = zero; secp256k1_ge_storage_cmov(&r, &a, 0); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); r = zero; a = max; secp256k1_ge_storage_cmov(&r, &a, 1); - CHECK(memcmp(&r, &max, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); a = zero; secp256k1_ge_storage_cmov(&r, &a, 1); - CHECK(memcmp(&r, &zero, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); a = one; secp256k1_ge_storage_cmov(&r, &a, 1); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); r = one; a = zero; secp256k1_ge_storage_cmov(&r, &a, 0); - CHECK(memcmp(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); } void run_cmov_tests(void) { @@ -5531,9 +5615,6 @@ void run_cmov_tests(void) { } int main(int argc, char **argv) { - unsigned char seed16[16] = {0}; - unsigned char run32[32] = {0}; - /* Disable buffering for stdout to improve reliability of getting * diagnostic information. Happens right at the start of main because * setbuf must be used before any other operation on the stream. */ @@ -5546,52 +5627,20 @@ int main(int argc, char **argv) { if (argc > 1) { count = strtol(argv[1], NULL, 0); } + printf("test count = %i\n", count); /* find random seed */ - if (argc > 2) { - int pos = 0; - const char* ch = argv[2]; - while (pos < 16 && ch[0] != 0 && ch[1] != 0) { - unsigned short sh; - if ((sscanf(ch, "%2hx", &sh)) == 1) { - seed16[pos] = sh; - } else { - break; - } - ch += 2; - pos++; - } - } else { - FILE *frand = fopen("/dev/urandom", "r"); - if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) { - uint64_t t = time(NULL) * (uint64_t)1337; - fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n"); - seed16[0] ^= t; - seed16[1] ^= t >> 8; - seed16[2] ^= t >> 16; - seed16[3] ^= t >> 24; - seed16[4] ^= t >> 32; - seed16[5] ^= t >> 40; - seed16[6] ^= t >> 48; - seed16[7] ^= t >> 56; - } - if (frand) { - fclose(frand); - } - } - secp256k1_rand_seed(seed16); - - printf("test count = %i\n", count); - printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + secp256k1_testrand_init(argc > 2 ? argv[2] : NULL); /* initialize */ run_context_tests(0); run_context_tests(1); run_scratch_tests(); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - if (secp256k1_rand_bits(1)) { - secp256k1_rand256(run32); - CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); + if (secp256k1_testrand_bits(1)) { + unsigned char rand32[32]; + secp256k1_testrand256(rand32); + CHECK(secp256k1_context_randomize(ctx, secp256k1_testrand_bits(1) ? rand32 : NULL)); } run_rand_bits(); @@ -5625,6 +5674,7 @@ int main(int argc, char **argv) { /* ecmult tests */ run_wnaf(); run_point_times_order(); + run_ecmult_near_split_bound(); run_ecmult_chain(); run_ecmult_constants(); run_ecmult_gen_blind(); @@ -5633,9 +5683,7 @@ int main(int argc, char **argv) { run_ec_combine(); /* endomorphism tests */ -#ifdef USE_ENDOMORPHISM run_endomorphism_tests(); -#endif /* EC point parser test */ run_ec_pubkey_parse_test(); @@ -5679,8 +5727,7 @@ int main(int argc, char **argv) { run_cmov_tests(); - secp256k1_rand256(run32); - printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); + secp256k1_testrand_finish(); /* shutdown */ secp256k1_context_destroy(ctx); diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c index 681ed80bd0..f4d5b8e176 100644 --- a/src/secp256k1/src/tests_exhaustive.c +++ b/src/secp256k1/src/tests_exhaustive.c @@ -18,7 +18,6 @@ #ifndef EXHAUSTIVE_TEST_ORDER /* see group_impl.h for allowable values */ #define EXHAUSTIVE_TEST_ORDER 13 -#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */ #endif #include "include/secp256k1.h" @@ -27,10 +26,7 @@ #include "secp256k1.c" #include "testrand_impl.h" -#ifdef ENABLE_MODULE_RECOVERY -#include "src/modules/recovery/main_impl.h" -#include "include/secp256k1_recovery.h" -#endif +static int count = 2; /** stolen from tests.c */ void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { @@ -62,7 +58,7 @@ void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { - secp256k1_rand256(bin); + secp256k1_testrand256(bin); if (secp256k1_fe_set_b32(x, bin)) { return; } @@ -70,6 +66,15 @@ void random_fe(secp256k1_fe *x) { } /** END stolen from tests.c */ +static uint32_t num_cores = 1; +static uint32_t this_core = 0; + +SECP256K1_INLINE static int skip_section(uint64_t* iter) { + if (num_cores == 1) return 0; + *iter += 0xe7037ed1a0b428dbULL; + return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; +} + int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int attempt) { @@ -90,91 +95,93 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha return 1; } -#ifdef USE_ENDOMORPHISM -void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) { +void test_exhaustive_endomorphism(const secp256k1_ge *group) { int i; - for (i = 0; i < order; i++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge res; secp256k1_ge_mul_lambda(&res, &group[i]); ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); } } -#endif -void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { +void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) { int i, j; + uint64_t iter = 0; /* Sanity-check (and check infinity functions) */ CHECK(secp256k1_ge_is_infinity(&group[0])); CHECK(secp256k1_gej_is_infinity(&groupj[0])); - for (i = 1; i < order; i++) { + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { CHECK(!secp256k1_ge_is_infinity(&group[i])); CHECK(!secp256k1_gej_is_infinity(&groupj[i])); } /* Check all addition formulae */ - for (j = 0; j < order; j++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { secp256k1_fe fe_inv; + if (skip_section(&iter)) continue; secp256k1_fe_inv(&fe_inv, &groupj[j].z); - for (i = 0; i < order; i++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge zless_gej; secp256k1_gej tmp; /* add_var */ secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); - ge_equals_gej(&group[(i + j) % order], &tmp); + ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); /* add_ge */ if (j > 0) { secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); - ge_equals_gej(&group[(i + j) % order], &tmp); + ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); } /* add_ge_var */ secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); - ge_equals_gej(&group[(i + j) % order], &tmp); + ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); /* add_zinv_var */ zless_gej.infinity = groupj[j].infinity; zless_gej.x = groupj[j].x; zless_gej.y = groupj[j].y; secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); - ge_equals_gej(&group[(i + j) % order], &tmp); + ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); } } /* Check doubling */ - for (i = 0; i < order; i++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_gej tmp; secp256k1_gej_double(&tmp, &groupj[i]); - ge_equals_gej(&group[(2 * i) % order], &tmp); + ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp); secp256k1_gej_double_var(&tmp, &groupj[i], NULL); - ge_equals_gej(&group[(2 * i) % order], &tmp); + ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp); } /* Check negation */ - for (i = 1; i < order; i++) { + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge tmp; secp256k1_gej tmpj; secp256k1_ge_neg(&tmp, &group[i]); - ge_equals_ge(&group[order - i], &tmp); + ge_equals_ge(&group[EXHAUSTIVE_TEST_ORDER - i], &tmp); secp256k1_gej_neg(&tmpj, &groupj[i]); - ge_equals_gej(&group[order - i], &tmpj); + ge_equals_gej(&group[EXHAUSTIVE_TEST_ORDER - i], &tmpj); } } -void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { +void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj) { int i, j, r_log; - for (r_log = 1; r_log < order; r_log++) { - for (j = 0; j < order; j++) { - for (i = 0; i < order; i++) { + uint64_t iter = 0; + for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + if (skip_section(&iter)) continue; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_gej tmp; secp256k1_scalar na, ng; secp256k1_scalar_set_int(&na, i); secp256k1_scalar_set_int(&ng, j); secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng); - ge_equals_gej(&group[(i * r_log + j) % order], &tmp); + ge_equals_gej(&group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER], &tmp); if (i > 0) { secp256k1_ecmult_const(&tmp, &group[i], &ng, 256); - ge_equals_gej(&group[(i * j) % order], &tmp); + ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp); } } } @@ -193,14 +200,16 @@ static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t return 1; } -void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { +void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) { int i, j, k, x, y; + uint64_t iter = 0; secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096); - for (i = 0; i < order; i++) { - for (j = 0; j < order; j++) { - for (k = 0; k < order; k++) { - for (x = 0; x < order; x++) { - for (y = 0; y < order; y++) { + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (j = 0; j < EXHAUSTIVE_TEST_ORDER; j++) { + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { + for (x = 0; x < EXHAUSTIVE_TEST_ORDER; x++) { + if (skip_section(&iter)) continue; + for (y = 0; y < EXHAUSTIVE_TEST_ORDER; y++) { secp256k1_gej tmp; secp256k1_scalar g_sc; ecmult_multi_data data; @@ -212,7 +221,7 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ data.pt[1] = group[y]; secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); - ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp); + ge_equals_gej(&group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER], &tmp); } } } @@ -221,22 +230,23 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ secp256k1_scratch_destroy(&ctx->error_callback, scratch); } -void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { +void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) { secp256k1_fe x; unsigned char x_bin[32]; k %= EXHAUSTIVE_TEST_ORDER; x = group[k].x; secp256k1_fe_normalize(&x); secp256k1_fe_get_b32(x_bin, &x); - secp256k1_scalar_set_b32(r, x_bin, NULL); + secp256k1_scalar_set_b32(r, x_bin, overflow); } -void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { +void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { int s, r, msg, key; - for (s = 1; s < order; s++) { - for (r = 1; r < order; r++) { - for (msg = 1; msg < order; msg++) { - for (key = 1; key < order; key++) { + uint64_t iter = 0; + for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { + for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) { + for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) { + for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) { secp256k1_ge nonconst_ge; secp256k1_ecdsa_signature sig; secp256k1_pubkey pk; @@ -245,6 +255,8 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr int k, should_verify; unsigned char msg32[32]; + if (skip_section(&iter)) continue; + secp256k1_scalar_set_int(&s_s, s); secp256k1_scalar_set_int(&r_s, r); secp256k1_scalar_set_int(&msg_s, msg); @@ -254,9 +266,9 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr /* Run through every k value that gives us this r and check that *one* works. * Note there could be none, there could be multiple, ECDSA is weird. */ should_verify = 0; - for (k = 0; k < order; k++) { + for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) { secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k); + r_from_k(&check_x_s, group, k, NULL); if (r_s == check_x_s) { secp256k1_scalar_set_int(&s_times_k_s, k); secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); @@ -281,13 +293,15 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr } } -void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { +void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { int i, j, k; + uint64_t iter = 0; /* Loop */ - for (i = 1; i < order; i++) { /* message */ - for (j = 1; j < order; j++) { /* key */ - for (k = 1; k < order; k++) { /* nonce */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */ + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */ + if (skip_section(&iter)) continue; + for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */ const int starting_k = k; secp256k1_ecdsa_signature sig; secp256k1_scalar sk, msg, r, s, expected_r; @@ -303,10 +317,10 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou /* Note that we compute expected_r *after* signing -- this is important * because our nonce-computing function function might change k during * signing. */ - r_from_k(&expected_r, group, k); + r_from_k(&expected_r, group, k, NULL); CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); /* Overflow means we've tried every possible nonce */ if (k < starting_k) { @@ -327,184 +341,114 @@ void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *grou } #ifdef ENABLE_MODULE_RECOVERY -void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - int i, j, k; - - /* Loop */ - for (i = 1; i < order; i++) { /* message */ - for (j = 1; j < order; j++) { /* key */ - for (k = 1; k < order; k++) { /* nonce */ - const int starting_k = k; - secp256k1_fe r_dot_y_normalized; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_scalar sk, msg, r, s, expected_r; - unsigned char sk32[32], msg32[32]; - int expected_recid; - int recid; - secp256k1_scalar_set_int(&msg, i); - secp256k1_scalar_set_int(&sk, j); - secp256k1_scalar_get_b32(sk32, &sk); - secp256k1_scalar_get_b32(msg32, &msg); - - secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); +#include "src/modules/recovery/tests_exhaustive_impl.h" +#endif - /* Check directly */ - secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); - r_from_k(&expected_r, group, k); - CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); - /* In computing the recid, there is an overflow condition that is disabled in - * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value - * will exceed the group order, and our signing code always holds out for r - * values that don't overflow, so with a proper overflow check the tests would - * loop indefinitely. */ - r_dot_y_normalized = group[k].y; - secp256k1_fe_normalize(&r_dot_y_normalized); - /* Also the recovery id is flipped depending if we hit the low-s branch */ - if ((k * s) % order == (i + r * j) % order) { - expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0; - } else { - expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1; - } - CHECK(recid == expected_recid); +#ifdef ENABLE_MODULE_EXTRAKEYS +#include "src/modules/extrakeys/tests_exhaustive_impl.h" +#endif - /* Convert to a standard sig then check */ - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); - /* Note that we compute expected_r *after* signing -- this is important - * because our nonce-computing function function might change k during - * signing. */ - r_from_k(&expected_r, group, k); - CHECK(r == expected_r); - CHECK((k * s) % order == (i + r * j) % order || - (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); +#ifdef ENABLE_MODULE_SCHNORRSIG +#include "src/modules/schnorrsig/tests_exhaustive_impl.h" +#endif - /* Overflow means we've tried every possible nonce */ - if (k < starting_k) { - break; - } - } +int main(int argc, char** argv) { + int i; + secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; + secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; + unsigned char rand32[32]; + secp256k1_context *ctx; + + /* Disable buffering for stdout to improve reliability of getting + * diagnostic information. Happens right at the start of main because + * setbuf must be used before any other operation on the stream. */ + setbuf(stdout, NULL); + /* Also disable buffering for stderr because it's not guaranteed that it's + * unbuffered on all systems. */ + setbuf(stderr, NULL); + + printf("Exhaustive tests for order %lu\n", (unsigned long)EXHAUSTIVE_TEST_ORDER); + + /* find iteration count */ + if (argc > 1) { + count = strtol(argv[1], NULL, 0); + } + printf("test count = %i\n", count); + + /* find random seed */ + secp256k1_testrand_init(argc > 2 ? argv[2] : NULL); + + /* set up split processing */ + if (argc > 4) { + num_cores = strtol(argv[3], NULL, 0); + this_core = strtol(argv[4], NULL, 0); + if (num_cores < 1 || this_core >= num_cores) { + fprintf(stderr, "Usage: %s [count] [seed] [numcores] [thiscore]\n", argv[0]); + return 1; } + printf("running tests for core %lu (out of [0..%lu])\n", (unsigned long)this_core, (unsigned long)num_cores - 1); } -} - -void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { - /* This is essentially a copy of test_exhaustive_verify, with recovery added */ - int s, r, msg, key; - for (s = 1; s < order; s++) { - for (r = 1; r < order; r++) { - for (msg = 1; msg < order; msg++) { - for (key = 1; key < order; key++) { - secp256k1_ge nonconst_ge; - secp256k1_ecdsa_recoverable_signature rsig; - secp256k1_ecdsa_signature sig; - secp256k1_pubkey pk; - secp256k1_scalar sk_s, msg_s, r_s, s_s; - secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; - int recid = 0; - int k, should_verify; - unsigned char msg32[32]; - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_set_int(&r_s, r); - secp256k1_scalar_set_int(&msg_s, msg); - secp256k1_scalar_set_int(&sk_s, key); - secp256k1_scalar_get_b32(msg32, &msg_s); + while (count--) { + /* Build context */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_testrand256(rand32); + CHECK(secp256k1_context_randomize(ctx, rand32)); + + /* Generate the entire group */ + secp256k1_gej_set_infinity(&groupj[0]); + secp256k1_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); + secp256k1_ge_set_gej(&group[i], &groupj[i]); + if (count != 0) { + /* Set a different random z-value for each Jacobian point, except z=1 + is used in the last iteration. */ + secp256k1_fe z; + random_fe(&z); + secp256k1_gej_rescale(&groupj[i], &z); + } - /* Verify by hand */ - /* Run through every k value that gives us this r and check that *one* works. - * Note there could be none, there could be multiple, ECDSA is weird. */ - should_verify = 0; - for (k = 0; k < order; k++) { - secp256k1_scalar check_x_s; - r_from_k(&check_x_s, group, k); - if (r_s == check_x_s) { - secp256k1_scalar_set_int(&s_times_k_s, k); - secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); - secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); - secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); - should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); - } - } - /* nb we have a "high s" rule */ - should_verify &= !secp256k1_scalar_is_high(&s_s); + /* Verify against ecmult_gen */ + { + secp256k1_scalar scalar_i; + secp256k1_gej generatedj; + secp256k1_ge generated; - /* We would like to try recovering the pubkey and checking that it matches, - * but pubkey recovery is impossible in the exhaustive tests (the reason - * being that there are 12 nonzero r values, 12 nonzero points, and no - * overlap between the sets, so there are no valid signatures). */ + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + secp256k1_ge_set_gej(&generated, &generatedj); - /* Verify by converting to a standard signature and calling verify */ - secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); - secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); - memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); - secp256k1_pubkey_save(&pk, &nonconst_ge); - CHECK(should_verify == - secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); - } + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); + CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); } } - } -} -#endif - -int main(void) { - int i; - secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; - secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; - /* Build context */ - secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + /* Run the tests */ + test_exhaustive_endomorphism(group); + test_exhaustive_addition(group, groupj); + test_exhaustive_ecmult(ctx, group, groupj); + test_exhaustive_ecmult_multi(ctx, group); + test_exhaustive_sign(ctx, group); + test_exhaustive_verify(ctx, group); - /* TODO set z = 1, then do num_tests runs with random z values */ +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery(ctx, group); +#endif +#ifdef ENABLE_MODULE_EXTRAKEYS + test_exhaustive_extrakeys(ctx, group); +#endif +#ifdef ENABLE_MODULE_SCHNORRSIG + test_exhaustive_schnorrsig(ctx); +#endif - /* Generate the entire group */ - secp256k1_gej_set_infinity(&groupj[0]); - secp256k1_ge_set_gej(&group[0], &groupj[0]); - for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { - /* Set a different random z-value for each Jacobian point */ - secp256k1_fe z; - random_fe(&z); - - secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); - secp256k1_ge_set_gej(&group[i], &groupj[i]); - secp256k1_gej_rescale(&groupj[i], &z); - - /* Verify against ecmult_gen */ - { - secp256k1_scalar scalar_i; - secp256k1_gej generatedj; - secp256k1_ge generated; - - secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - secp256k1_ge_set_gej(&generated, &generatedj); - - CHECK(group[i].infinity == 0); - CHECK(generated.infinity == 0); - CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); - CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); - } + secp256k1_context_destroy(ctx); } - /* Run the tests */ -#ifdef USE_ENDOMORPHISM - test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER); -#endif - test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_ecmult_multi(ctx, group, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); + secp256k1_testrand_finish(); -#ifdef ENABLE_MODULE_RECOVERY - test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); - test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); -#endif - - secp256k1_context_destroy(ctx); + printf("no problems found\n"); return 0; } - diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h index a5cbe03ef5..3a88a41bc6 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/src/util.h @@ -216,6 +216,24 @@ static SECP256K1_INLINE void memczero(void *s, size_t len, int flag) { } } +/** Semantics like memcmp. Variable-time. + * + * We use this to avoid possible compiler bugs with memcmp, e.g. + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95189 + */ +static SECP256K1_INLINE int secp256k1_memcmp_var(const void *s1, const void *s2, size_t n) { + const unsigned char *p1 = s1, *p2 = s2; + size_t i; + + for (i = 0; i < n; i++) { + int diff = p1[i] - p2[i]; + if (diff != 0) { + return diff; + } + } + return 0; +} + /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized and non-negative.*/ static SECP256K1_INLINE void secp256k1_int_cmov(int *r, const int *a, int flag) { unsigned int mask0, mask1, r_masked, a_masked; diff --git a/src/secp256k1/src/valgrind_ctime_test.c b/src/secp256k1/src/valgrind_ctime_test.c index e676a8326c..3169e3651c 100644 --- a/src/secp256k1/src/valgrind_ctime_test.c +++ b/src/secp256k1/src/valgrind_ctime_test.c @@ -9,19 +9,19 @@ #include "assumptions.h" #include "util.h" -#if ENABLE_MODULE_ECDH +#ifdef ENABLE_MODULE_ECDH # include "include/secp256k1_ecdh.h" #endif -#if ENABLE_MODULE_RECOVERY +#ifdef ENABLE_MODULE_RECOVERY # include "include/secp256k1_recovery.h" #endif -#if ENABLE_MODULE_EXTRAKEYS +#ifdef ENABLE_MODULE_EXTRAKEYS # include "include/secp256k1_extrakeys.h" #endif -#if ENABLE_MODULE_SCHNORRSIG +#ifdef ENABLE_MODULE_SCHNORRSIG #include "include/secp256k1_schnorrsig.h" #endif @@ -37,11 +37,11 @@ int main(void) { unsigned char key[32]; unsigned char sig[74]; unsigned char spubkey[33]; -#if ENABLE_MODULE_RECOVERY +#ifdef ENABLE_MODULE_RECOVERY secp256k1_ecdsa_recoverable_signature recoverable_signature; int recid; #endif -#if ENABLE_MODULE_EXTRAKEYS +#ifdef ENABLE_MODULE_EXTRAKEYS secp256k1_keypair keypair; #endif @@ -81,7 +81,7 @@ int main(void) { CHECK(ret); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); -#if ENABLE_MODULE_ECDH +#ifdef ENABLE_MODULE_ECDH /* Test ECDH. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); @@ -89,7 +89,7 @@ int main(void) { CHECK(ret == 1); #endif -#if ENABLE_MODULE_RECOVERY +#ifdef ENABLE_MODULE_RECOVERY /* Test signing a recoverable signature. */ VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); @@ -129,7 +129,7 @@ int main(void) { CHECK(ret); /* Test keypair_create and keypair_xonly_tweak_add. */ -#if ENABLE_MODULE_EXTRAKEYS +#ifdef ENABLE_MODULE_EXTRAKEYS VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_keypair_create(ctx, &keypair, key); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); @@ -142,7 +142,7 @@ int main(void) { CHECK(ret == 1); #endif -#if ENABLE_MODULE_SCHNORRSIG +#ifdef ENABLE_MODULE_SCHNORRSIG VALGRIND_MAKE_MEM_UNDEFINED(key, 32); ret = secp256k1_keypair_create(ctx, &keypair, key); VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); diff --git a/src/serialize.h b/src/serialize.h index 7a94e704b2..d9ca984f9c 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -24,7 +24,11 @@ #include <prevector.h> #include <span.h> -static const unsigned int MAX_SIZE = 0x02000000; +/** + * The maximum size of a serialized object in bytes or number of elements + * (for eg vectors) when the size is encoded as CompactSize. + */ +static constexpr uint64_t MAX_SIZE = 0x02000000; /** Maximum amount of memory (in bytes) to allocate at once when deserializing vectors. */ static const unsigned int MAX_VECTOR_ALLOCATE = 5000000; @@ -304,8 +308,14 @@ void WriteCompactSize(Stream& os, uint64_t nSize) return; } +/** + * Decode a CompactSize-encoded variable-length integer. + * + * As these are primarily used to encode the size of vector-like serializations, by default a range + * check is performed. When used as a generic number encoding, range_check should be set to false. + */ template<typename Stream> -uint64_t ReadCompactSize(Stream& is) +uint64_t ReadCompactSize(Stream& is, bool range_check = true) { uint8_t chSize = ser_readdata8(is); uint64_t nSizeRet = 0; @@ -331,8 +341,9 @@ uint64_t ReadCompactSize(Stream& is) if (nSizeRet < 0x100000000ULL) throw std::ios_base::failure("non-canonical ReadCompactSize()"); } - if (nSizeRet > (uint64_t)MAX_SIZE) + if (range_check && nSizeRet > MAX_SIZE) { throw std::ios_base::failure("ReadCompactSize(): size too large"); + } return nSizeRet; } @@ -466,7 +477,7 @@ static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T& #define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj) #define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj) -#define COMPACTSIZE(obj) Using<CompactSizeFormatter>(obj) +#define COMPACTSIZE(obj) Using<CompactSizeFormatter<true>>(obj) #define LIMITED_STRING(obj,n) Using<LimitedStringFormatter<n>>(obj) /** Serialization wrapper class for integers in VarInt format. */ @@ -529,12 +540,13 @@ struct CustomUintFormatter template<int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true>; /** Formatter for integers in CompactSize format. */ +template<bool RangeCheck> struct CompactSizeFormatter { template<typename Stream, typename I> void Unser(Stream& s, I& v) { - uint64_t n = ReadCompactSize<Stream>(s); + uint64_t n = ReadCompactSize<Stream>(s, RangeCheck); if (n < std::numeric_limits<I>::min() || n > std::numeric_limits<I>::max()) { throw std::ios_base::failure("CompactSize exceeds limit of type"); } diff --git a/src/shutdown.cpp b/src/shutdown.cpp index dec497d8ec..df5f996022 100644 --- a/src/shutdown.cpp +++ b/src/shutdown.cpp @@ -1,23 +1,112 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <shutdown.h> +#include <config/bitcoin-config.h> + +#include <assert.h> #include <atomic> +#ifdef WIN32 +#include <condition_variable> +#else +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#endif static std::atomic<bool> fRequestShutdown(false); +#ifdef WIN32 +/** On windows it is possible to simply use a condition variable. */ +std::mutex g_shutdown_mutex; +std::condition_variable g_shutdown_cv; +#else +/** On UNIX-like operating systems use the self-pipe trick. + * Index 0 will be the read end of the pipe, index 1 the write end. + */ +static int g_shutdown_pipe[2] = {-1, -1}; +#endif + +bool InitShutdownState() +{ +#ifndef WIN32 +#if HAVE_O_CLOEXEC + // If we can, make sure that the file descriptors are closed on exec() + // to prevent interference. + if (pipe2(g_shutdown_pipe, O_CLOEXEC) != 0) { + return false; + } +#else + if (pipe(g_shutdown_pipe) != 0) { + return false; + } +#endif +#endif + return true; +} void StartShutdown() { +#ifdef WIN32 + std::unique_lock<std::mutex> lk(g_shutdown_mutex); fRequestShutdown = true; + g_shutdown_cv.notify_one(); +#else + // This must be reentrant and safe for calling in a signal handler, so using a condition variable is not safe. + // Make sure that the token is only written once even if multiple threads call this concurrently or in + // case of a reentrant signal. + if (!fRequestShutdown.exchange(true)) { + // Write an arbitrary byte to the write end of the shutdown pipe. + const char token = 'x'; + while (true) { + int result = write(g_shutdown_pipe[1], &token, 1); + if (result < 0) { + // Failure. It's possible that the write was interrupted by another signal. + // Other errors are unexpected here. + assert(errno == EINTR); + } else { + assert(result == 1); + break; + } + } + } +#endif } + void AbortShutdown() { + if (fRequestShutdown) { + // Cancel existing shutdown by waiting for it, this will reset condition flags and remove + // the shutdown token from the pipe. + WaitForShutdown(); + } fRequestShutdown = false; } + bool ShutdownRequested() { return fRequestShutdown; } + +void WaitForShutdown() +{ +#ifdef WIN32 + std::unique_lock<std::mutex> lk(g_shutdown_mutex); + g_shutdown_cv.wait(lk, [] { return fRequestShutdown.load(); }); +#else + char token; + while (true) { + int result = read(g_shutdown_pipe[0], &token, 1); + if (result < 0) { + // Failure. Check if the read was interrupted by a signal. + // Other errors are unexpected here. + assert(errno == EINTR); + } else { + assert(result == 1); + break; + } + } +#endif +} diff --git a/src/shutdown.h b/src/shutdown.h index 3ed851c789..b2fbdb8cfb 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -1,13 +1,30 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SHUTDOWN_H #define BITCOIN_SHUTDOWN_H +/** Initialize shutdown state. This must be called before using either StartShutdown(), + * AbortShutdown() or WaitForShutdown(). Calling ShutdownRequested() is always safe. + */ +bool InitShutdownState(); + +/** Request shutdown of the application. */ void StartShutdown(); + +/** Clear shutdown flag. Only use this during init (before calling WaitForShutdown in any + * thread), or in the unit tests. Calling it in other circumstances will cause a race condition. + */ void AbortShutdown(); + +/** Returns true if a shutdown is requested, false otherwise. */ bool ShutdownRequested(); +/** Wait for StartShutdown to be called in any thread. This can only be used + * from a single thread. + */ +void WaitForShutdown(); + #endif diff --git a/src/span.h b/src/span.h index 4afb383a59..830164514b 100644 --- a/src/span.h +++ b/src/span.h @@ -18,6 +18,16 @@ #define ASSERT_IF_DEBUG(x) #endif +#if defined(__clang__) +#if __has_attribute(lifetimebound) +#define SPAN_ATTR_LIFETIMEBOUND [[clang::lifetimebound]] +#else +#define SPAN_ATTR_LIFETIMEBOUND +#endif +#else +#define SPAN_ATTR_LIFETIMEBOUND +#endif + /** A Span is an object that can refer to a contiguous sequence of objects. * * It implements a subset of C++20's std::span. @@ -84,6 +94,14 @@ class Span C* m_data; std::size_t m_size; + template <class T> + struct is_Span_int : public std::false_type {}; + template <class T> + struct is_Span_int<Span<T>> : public std::true_type {}; + template <class T> + struct is_Span : public is_Span_int<typename std::remove_cv<T>::type>{}; + + public: constexpr Span() noexcept : m_data(nullptr), m_size(0) {} @@ -134,8 +152,19 @@ public: * To prevent surprises, only Spans for constant value types are supported when passing in temporaries. * Note that this restriction does not exist when converting arrays or other Spans (see above). */ - template <typename V, typename std::enable_if<(std::is_const<C>::value || std::is_lvalue_reference<V>::value) && std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, int>::type = 0> - constexpr Span(V&& v) noexcept : m_data(v.data()), m_size(v.size()) {} + template <typename V> + constexpr Span(V& other SPAN_ATTR_LIFETIMEBOUND, + typename std::enable_if<!is_Span<V>::value && + std::is_convertible<typename std::remove_pointer<decltype(std::declval<V&>().data())>::type (*)[], C (*)[]>::value && + std::is_convertible<decltype(std::declval<V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) + : m_data(other.data()), m_size(other.size()){} + + template <typename V> + constexpr Span(const V& other SPAN_ATTR_LIFETIMEBOUND, + typename std::enable_if<!is_Span<V>::value && + std::is_convertible<typename std::remove_pointer<decltype(std::declval<const V&>().data())>::type (*)[], C (*)[]>::value && + std::is_convertible<decltype(std::declval<const V&>().size()), std::size_t>::value, std::nullptr_t>::type = nullptr) + : m_data(other.data()), m_size(other.size()){} constexpr C* data() const noexcept { return m_data; } constexpr C* begin() const noexcept { return m_data; } @@ -192,9 +221,9 @@ public: /** MakeSpan for arrays: */ template <typename A, int N> Span<A> constexpr MakeSpan(A (&a)[N]) { return Span<A>(a, N); } /** MakeSpan for temporaries / rvalue references, only supporting const output. */ -template <typename V> constexpr auto MakeSpan(V&& v) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); } +template <typename V> constexpr auto MakeSpan(V&& v SPAN_ATTR_LIFETIMEBOUND) -> typename std::enable_if<!std::is_lvalue_reference<V>::value, Span<const typename std::remove_pointer<decltype(v.data())>::type>>::type { return std::forward<V>(v); } /** MakeSpan for (lvalue) references, supporting mutable output. */ -template <typename V> constexpr auto MakeSpan(V& v) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; } +template <typename V> constexpr auto MakeSpan(V& v SPAN_ATTR_LIFETIMEBOUND) -> Span<typename std::remove_pointer<decltype(v.data())>::type> { return v; } /** Pop the last element off a span, and return a reference to that element. */ template <typename T> diff --git a/src/streams.h b/src/streams.h index 6ce8065da8..fce411d3df 100644 --- a/src/streams.h +++ b/src/streams.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -60,6 +60,7 @@ public: int GetVersion() const { return nVersion; } int GetType() const { return nType; } size_t size() const { return stream->size(); } + void ignore(size_t size) { return stream->ignore(size); } }; /* Minimal stream for overwriting and/or appending to an existing byte vector diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp index 26de780f29..6965f40253 100644 --- a/src/support/lockedpool.cpp +++ b/src/support/lockedpool.cpp @@ -65,7 +65,7 @@ void* Arena::alloc(size_t size) // Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key. // This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review", - // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit + // Wilson et. al. 1995, https://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit // policies seem to work well in practice. auto size_ptr_it = size_to_free_chunk.lower_bound(size); if (size_ptr_it == size_to_free_chunk.end()) diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h index b9e2e99d1a..03e4e371a3 100644 --- a/src/support/lockedpool.h +++ b/src/support/lockedpool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/sync.cpp b/src/sync.cpp index 322198a852..a2b62c2286 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -14,9 +14,11 @@ #include <util/threadnames.h> #include <map> +#include <mutex> #include <set> #include <system_error> #include <thread> +#include <type_traits> #include <unordered_map> #include <utility> #include <vector> @@ -135,16 +137,52 @@ static void potential_deadlock_detected(const LockPair& mismatch, const LockStac throw std::logic_error(strprintf("potential deadlock detected: %s -> %s -> %s", mutex_b, mutex_a, mutex_b)); } -static void push_lock(void* c, const CLockLocation& locklocation) +static void double_lock_detected(const void* mutex, const LockStack& lock_stack) { + LogPrintf("DOUBLE LOCK DETECTED\n"); + LogPrintf("Lock order:\n"); + for (const LockStackItem& i : lock_stack) { + if (i.first == mutex) { + LogPrintf(" (*)"); /* Continued */ + } + LogPrintf(" %s\n", i.second.ToString()); + } + if (g_debug_lockorder_abort) { + tfm::format(std::cerr, + "Assertion failed: detected double lock for %s, details in debug log.\n", + lock_stack.back().second.ToString()); + abort(); + } + throw std::logic_error("double lock detected"); +} + +template <typename MutexType> +static void push_lock(MutexType* c, const CLockLocation& locklocation) +{ + constexpr bool is_recursive_mutex = + std::is_base_of<RecursiveMutex, MutexType>::value || + std::is_base_of<std::recursive_mutex, MutexType>::value; + LockData& lockdata = GetLockData(); std::lock_guard<std::mutex> lock(lockdata.dd_mutex); LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()]; lock_stack.emplace_back(c, locklocation); - for (const LockStackItem& i : lock_stack) { - if (i.first == c) - break; + for (size_t j = 0; j < lock_stack.size() - 1; ++j) { + const LockStackItem& i = lock_stack[j]; + if (i.first == c) { + if (is_recursive_mutex) { + break; + } + // It is not a recursive mutex and it appears in the stack two times: + // at position `j` and at the end (which we added just before this loop). + // Can't allow locking the same (non-recursive) mutex two times from the + // same thread as that results in an undefined behavior. + auto lock_stack_copy = lock_stack; + lock_stack.pop_back(); + double_lock_detected(c, lock_stack_copy); + // double_lock_detected() does not return. + } const LockPair p1 = std::make_pair(i.first, c); if (lockdata.lockorders.count(p1)) @@ -175,27 +213,40 @@ static void pop_lock() } } -void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) +template <typename MutexType> +void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry) { push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName())); } +template void EnterCritical(const char*, const char*, int, Mutex*, bool); +template void EnterCritical(const char*, const char*, int, RecursiveMutex*, bool); +template void EnterCritical(const char*, const char*, int, std::mutex*, bool); +template void EnterCritical(const char*, const char*, int, std::recursive_mutex*, bool); void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) { - { - LockData& lockdata = GetLockData(); - std::lock_guard<std::mutex> lock(lockdata.dd_mutex); - - const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()]; - if (!lock_stack.empty()) { - const auto& lastlock = lock_stack.back(); - if (lastlock.first == cs) { - lockname = lastlock.second.Name(); - return; - } + LockData& lockdata = GetLockData(); + std::lock_guard<std::mutex> lock(lockdata.dd_mutex); + + const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()]; + if (!lock_stack.empty()) { + const auto& lastlock = lock_stack.back(); + if (lastlock.first == cs) { + lockname = lastlock.second.Name(); + return; } } - throw std::system_error(EPERM, std::generic_category(), strprintf("%s:%s %s was not most recent critical section locked", file, line, guardname)); + + LogPrintf("INCONSISTENT LOCK ORDER DETECTED\n"); + LogPrintf("Current lock order (least recent first) is:\n"); + for (const LockStackItem& i : lock_stack) { + LogPrintf(" %s\n", i.second.ToString()); + } + if (g_debug_lockorder_abort) { + tfm::format(std::cerr, "%s:%s %s was not most recent critical section locked, details in debug log.\n", file, line, guardname); + abort(); + } + throw std::logic_error(strprintf("%s was not most recent critical section locked", guardname)); } void LeaveCritical() diff --git a/src/sync.h b/src/sync.h index 41f4e43bdd..53213c2089 100644 --- a/src/sync.h +++ b/src/sync.h @@ -48,7 +48,8 @@ LEAVE_CRITICAL_SECTION(mutex); // no RAII /////////////////////////////// #ifdef DEBUG_LOCKORDER -void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); +template <typename MutexType> +void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false); void LeaveCritical(); void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line); std::string LocksHeld(); @@ -66,7 +67,8 @@ bool LockStackEmpty(); */ extern bool g_debug_lockorder_abort; #else -inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} +template <typename MutexType> +inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexType* cs, bool fTry = false) {} inline void LeaveCritical() {} inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {} template <typename MutexType> @@ -135,7 +137,7 @@ class SCOPED_LOCKABLE UniqueLock : public Base private: void Enter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex())); + EnterCritical(pszName, pszFile, nLine, Base::mutex()); #ifdef DEBUG_LOCKCONTENTION if (!Base::try_lock()) { PrintLockContention(pszName, pszFile, nLine); @@ -148,7 +150,7 @@ private: bool TryEnter(const char* pszName, const char* pszFile, int nLine) { - EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex()), true); + EnterCritical(pszName, pszFile, nLine, Base::mutex(), true); Base::try_lock(); if (!Base::owns_lock()) LeaveCritical(); @@ -205,7 +207,7 @@ public: ~reverse_lock() { templock.swap(lock); - EnterCritical(lockname.c_str(), file.c_str(), line, (void*)lock.mutex()); + EnterCritical(lockname.c_str(), file.c_str(), line, lock.mutex()); lock.lock(); } @@ -236,14 +238,16 @@ using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove #define ENTER_CRITICAL_SECTION(cs) \ { \ - EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \ + EnterCritical(#cs, __FILE__, __LINE__, &cs); \ (cs).lock(); \ } -#define LEAVE_CRITICAL_SECTION(cs) \ - { \ - (cs).unlock(); \ - LeaveCritical(); \ +#define LEAVE_CRITICAL_SECTION(cs) \ + { \ + std::string lockname; \ + CheckLastCritical((void*)(&cs), lockname, #cs, __FILE__, __LINE__); \ + (cs).unlock(); \ + LeaveCritical(); \ } //! Run code while locking a mutex. @@ -254,7 +258,22 @@ using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove //! //! int val = WITH_LOCK(cs, return shared_val); //! -#define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }() +//! Note: +//! +//! Since the return type deduction follows that of decltype(auto), while the +//! deduced type of: +//! +//! WITH_LOCK(cs, return {int i = 1; return i;}); +//! +//! is int, the deduced type of: +//! +//! WITH_LOCK(cs, return {int j = 1; return (j);}); +//! +//! is &int, a reference to a local variable +//! +//! The above is detectable at compile-time with the -Wreturn-local-addr flag in +//! gcc and the -Wreturn-stack-address flag in clang, both enabled by default. +#define WITH_LOCK(cs, code) [&]() -> decltype(auto) { LOCK(cs); code; }() class CSemaphore { diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 25fdd64568..37ff8a9afe 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -71,7 +71,7 @@ public: } // Simulates connection failure so that we can test eviction of offline nodes - void SimConnFail(CService& addr) + void SimConnFail(const CService& addr) { LOCK(cs); int64_t nLastSuccess = 1; diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp index e20900ed13..1a39498899 100644 --- a/src/test/amount_tests.cpp +++ b/src/test/amount_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(BinaryOperatorTest) BOOST_CHECK(a <= a); BOOST_CHECK(b >= a); BOOST_CHECK(b >= b); - // a should be 0.00000002 BTC/kB now + // a should be 0.00000002 BTC/kvB now a += a; BOOST_CHECK(a == b); } @@ -107,7 +107,9 @@ BOOST_AUTO_TEST_CASE(ToStringTest) { CFeeRate feeRate; feeRate = CFeeRate(1); - BOOST_CHECK_EQUAL(feeRate.ToString(), "0.00000001 BTC/kB"); + BOOST_CHECK_EQUAL(feeRate.ToString(), "0.00000001 BTC/kvB"); + BOOST_CHECK_EQUAL(feeRate.ToString(FeeEstimateMode::BTC_KVB), "0.00000001 BTC/kvB"); + BOOST_CHECK_EQUAL(feeRate.ToString(FeeEstimateMode::SAT_VB), "0.001 sat/vB"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index d519eca859..3f7c5e99ee 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -6,6 +6,9 @@ #include <util/strencodings.h> #include <boost/test/unit_test.hpp> +#include <string> + +using namespace std::literals; BOOST_FIXTURE_TEST_SUITE(base32_tests, BasicTestingSetup) @@ -26,14 +29,14 @@ BOOST_AUTO_TEST_CASE(base32_testvectors) // Decoding strings with embedded NUL characters should fail bool failure; - (void)DecodeBase32(std::string("invalid", 7), &failure); - BOOST_CHECK_EQUAL(failure, true); - (void)DecodeBase32(std::string("AWSX3VPP", 8), &failure); - BOOST_CHECK_EQUAL(failure, false); - (void)DecodeBase32(std::string("AWSX3VPP\0invalid", 16), &failure); - BOOST_CHECK_EQUAL(failure, true); - (void)DecodeBase32(std::string("AWSX3VPPinvalid", 15), &failure); - BOOST_CHECK_EQUAL(failure, true); + (void)DecodeBase32("invalid\0"s, &failure); // correct size, invalid due to \0 + BOOST_CHECK(failure); + (void)DecodeBase32("AWSX3VPP"s, &failure); // valid + BOOST_CHECK(!failure); + (void)DecodeBase32("AWSX3VPP\0invalid"s, &failure); // correct size, invalid due to \0 + BOOST_CHECK(failure); + (void)DecodeBase32("AWSX3VPPinvalid"s, &failure); // invalid size + BOOST_CHECK(failure); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index 6a636f2574..dd760fe999 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,7 +12,9 @@ #include <univalue.h> #include <boost/test/unit_test.hpp> +#include <string> +using namespace std::literals; extern UniValue read_json(const std::string& jsondata); @@ -58,14 +60,14 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) BOOST_CHECK_MESSAGE(result.size() == expected.size() && std::equal(result.begin(), result.end(), expected.begin()), strTest); } - BOOST_CHECK(!DecodeBase58("invalid", result, 100)); - BOOST_CHECK(!DecodeBase58(std::string("invalid"), result, 100)); - BOOST_CHECK(!DecodeBase58(std::string("\0invalid", 8), result, 100)); + BOOST_CHECK(!DecodeBase58("invalid"s, result, 100)); + BOOST_CHECK(!DecodeBase58("invalid\0"s, result, 100)); + BOOST_CHECK(!DecodeBase58("\0invalid"s, result, 100)); - BOOST_CHECK(DecodeBase58(std::string("good", 4), result, 100)); - BOOST_CHECK(!DecodeBase58(std::string("bad0IOl", 7), result, 100)); - BOOST_CHECK(!DecodeBase58(std::string("goodbad0IOl", 11), result, 100)); - BOOST_CHECK(!DecodeBase58(std::string("good\0bad0IOl", 12), result, 100)); + BOOST_CHECK(DecodeBase58("good"s, result, 100)); + BOOST_CHECK(!DecodeBase58("bad0IOl"s, result, 100)); + BOOST_CHECK(!DecodeBase58("goodbad0IOl"s, result, 100)); + BOOST_CHECK(!DecodeBase58("good\0bad0IOl"s, result, 100)); // check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end. BOOST_CHECK(!DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t a", result, 3)); @@ -73,10 +75,10 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) std::vector<unsigned char> expected = ParseHex("971a55"); BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); - BOOST_CHECK(DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh", 21), result, 100)); - BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oi", 21), result, 100)); - BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh0IOl", 25), result, 100)); - BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh\00IOl", 26), result, 100)); + BOOST_CHECK(DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oh"s, result, 100)); + BOOST_CHECK(!DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oi"s, result, 100)); + BOOST_CHECK(!DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oh0IOl"s, result, 100)); + BOOST_CHECK(!DecodeBase58Check("3vQB7B6MrGQZaxCuFg4oh\0" "0IOl"s, result, 100)); } BOOST_AUTO_TEST_CASE(base58_random_encode_decode) diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index 5927eab6cf..bb8d102bd0 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -6,6 +6,9 @@ #include <util/strencodings.h> #include <boost/test/unit_test.hpp> +#include <string> + +using namespace std::literals; BOOST_FIXTURE_TEST_SUITE(base64_tests, BasicTestingSetup) @@ -23,14 +26,14 @@ BOOST_AUTO_TEST_CASE(base64_testvectors) // Decoding strings with embedded NUL characters should fail bool failure; - (void)DecodeBase64(std::string("invalid", 7), &failure); - BOOST_CHECK_EQUAL(failure, true); - (void)DecodeBase64(std::string("nQB/pZw=", 8), &failure); - BOOST_CHECK_EQUAL(failure, false); - (void)DecodeBase64(std::string("nQB/pZw=\0invalid", 16), &failure); - BOOST_CHECK_EQUAL(failure, true); - (void)DecodeBase64(std::string("nQB/pZw=invalid", 15), &failure); - BOOST_CHECK_EQUAL(failure, true); + (void)DecodeBase64("invalid\0"s, &failure); + BOOST_CHECK(failure); + (void)DecodeBase64("nQB/pZw="s, &failure); + BOOST_CHECK(!failure); + (void)DecodeBase64("nQB/pZw=\0invalid"s, &failure); + BOOST_CHECK(failure); + (void)DecodeBase64("nQB/pZw=invalid\0"s, &failure); + BOOST_CHECK(failure); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 14cf1a4a76..9dfbd7ba7c 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index 178c261365..8eb4dbc592 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 8348810ac1..76d6727044 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -26,7 +26,7 @@ static const unsigned int QUEUE_BATCH_SIZE = 128; static const int SCRIPT_CHECK_THREADS = 3; struct FakeCheck { - bool operator()() + bool operator()() const { return true; } @@ -47,7 +47,7 @@ struct FailingCheck { bool fails; FailingCheck(bool _fails) : fails(_fails){}; FailingCheck() : fails(true){}; - bool operator()() + bool operator()() const { return !fails; } @@ -76,7 +76,7 @@ struct UniqueCheck { struct MemoryCheck { static std::atomic<size_t> fake_allocated_memory; bool b {false}; - bool operator()() + bool operator()() const { return true; } @@ -107,7 +107,7 @@ struct FrozenCleanupCheck { // Freezing can't be the default initialized behavior given how the queue // swaps in default initialized Checks. bool should_freeze {false}; - bool operator()() + bool operator()() const { return true; } @@ -148,10 +148,7 @@ typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue; static void Correct_Queue_range(std::vector<size_t> range) { auto small_queue = MakeUnique<Correct_Queue>(QUEUE_BATCH_SIZE); - boost::thread_group tg; - for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) { - tg.create_thread([&]{small_queue->Thread();}); - } + small_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS); // Make vChecks here to save on malloc (this test can be slow...) std::vector<FakeCheckCheckCompletion> vChecks; for (const size_t i : range) { @@ -168,8 +165,7 @@ static void Correct_Queue_range(std::vector<size_t> range) BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i); } } - tg.interrupt_all(); - tg.join_all(); + small_queue->StopWorkerThreads(); } /** Test that 0 checks is correct @@ -212,11 +208,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random) BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) { auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE); - - boost::thread_group tg; - for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) { - tg.create_thread([&]{fail_queue->Thread();}); - } + fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS); for (size_t i = 0; i < 1001; ++i) { CCheckQueueControl<FailingCheck> control(fail_queue.get()); @@ -237,18 +229,14 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) BOOST_REQUIRE(success); } } - tg.interrupt_all(); - tg.join_all(); + fail_queue->StopWorkerThreads(); } // Test that a block validation which fails does not interfere with // future blocks, ie, the bad state is cleared. BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) { auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE); - boost::thread_group tg; - for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) { - tg.create_thread([&]{fail_queue->Thread();}); - } + fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS); for (auto times = 0; times < 10; ++times) { for (const bool end_fails : {true, false}) { @@ -263,8 +251,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) BOOST_REQUIRE(r != end_fails); } } - tg.interrupt_all(); - tg.join_all(); + fail_queue->StopWorkerThreads(); } // Test that unique checks are actually all called individually, rather than @@ -273,11 +260,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) { auto queue = MakeUnique<Unique_Queue>(QUEUE_BATCH_SIZE); - boost::thread_group tg; - for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) { - tg.create_thread([&]{queue->Thread();}); - - } + queue->StartWorkerThreads(SCRIPT_CHECK_THREADS); size_t COUNT = 100000; size_t total = COUNT; @@ -300,8 +283,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) } BOOST_REQUIRE(r); } - tg.interrupt_all(); - tg.join_all(); + queue->StopWorkerThreads(); } @@ -313,10 +295,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) { auto queue = MakeUnique<Memory_Queue>(QUEUE_BATCH_SIZE); - boost::thread_group tg; - for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) { - tg.create_thread([&]{queue->Thread();}); - } + queue->StartWorkerThreads(SCRIPT_CHECK_THREADS); for (size_t i = 0; i < 1000; ++i) { size_t total = i; { @@ -335,8 +314,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) } BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U); } - tg.interrupt_all(); - tg.join_all(); + queue->StopWorkerThreads(); } // Test that a new verification cannot occur until all checks @@ -344,11 +322,8 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) { auto queue = MakeUnique<FrozenCleanup_Queue>(QUEUE_BATCH_SIZE); - boost::thread_group tg; bool fails = false; - for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) { - tg.create_thread([&]{queue->Thread();}); - } + queue->StartWorkerThreads(SCRIPT_CHECK_THREADS); std::thread t0([&]() { CCheckQueueControl<FrozenCleanupCheck> control(queue.get()); std::vector<FrozenCleanupCheck> vChecks(1); @@ -367,7 +342,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) } // Try to get control of the queue a bunch of times for (auto x = 0; x < 100 && !fails; ++x) { - fails = queue->ControlMutex.try_lock(); + fails = queue->m_control_mutex.try_lock(); } { // Unfreeze (we need lock n case of spurious wakeup) @@ -378,9 +353,8 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) FrozenCleanupCheck::cv.notify_one(); // Wait for control to finish t0.join(); - tg.interrupt_all(); - tg.join_all(); BOOST_REQUIRE(!fails); + queue->StopWorkerThreads(); } @@ -431,7 +405,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks) cv.wait(l, [&](){return has_lock;}); bool fails = false; for (auto x = 0; x < 100 && !fails; ++x) { - fails = queue->ControlMutex.try_lock(); + fails = queue->m_control_mutex.try_lock(); } has_tried = true; cv.notify_one(); @@ -445,4 +419,3 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks) } } BOOST_AUTO_TEST_SUITE_END() - diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 173ec5e3d9..06db3b846e 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -38,7 +38,7 @@ class CCoinsViewTest : public CCoinsView std::map<COutPoint, Coin> map_; public: - NODISCARD bool GetCoin(const COutPoint& outpoint, Coin& coin) const override + [[nodiscard]] bool GetCoin(const COutPoint& outpoint, Coin& coin) const override { std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); if (it == map_.end()) { diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 0ad5066603..7358b246b6 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -14,7 +14,9 @@ #include <crypto/sha256.h> #include <crypto/sha3.h> #include <crypto/sha512.h> +#include <crypto/muhash.h> #include <random.h> +#include <streams.h> #include <test/util/setup_common.h> #include <util/strencodings.h> @@ -857,4 +859,92 @@ BOOST_AUTO_TEST_CASE(sha3_256_tests) TestSHA3_256("72c57c359e10684d0517e46653a02d18d29eff803eb009e4d5eb9e95add9ad1a4ac1f38a70296f3a369a16985ca3c957de2084cdc9bdd8994eb59b8815e0debad4ec1f001feac089820db8becdaf896aaf95721e8674e5d476b43bd2b873a7d135cd685f545b438210f9319e4dcd55986c85303c1ddf18dc746fe63a409df0a998ed376eb683e16c09e6e9018504152b3e7628ef350659fb716e058a5263a18823d2f2f6ee6a8091945a48ae1c5cb1694cf2c1fe76ef9177953afe8899cfa2b7fe0603bfa3180937dadfb66fbbdd119bbf8063338aa4a699075a3bfdbae8db7e5211d0917e9665a702fc9b0a0a901d08bea97654162d82a9f05622b060b634244779c33427eb7a29353a5f48b07cbefa72f3622ac5900bef77b71d6b314296f304c8426f451f32049b1f6af156a9dab702e8907d3cd72bb2c50493f4d593e731b285b70c803b74825b3524cda3205a8897106615260ac93c01c5ec14f5b11127783989d1824527e99e04f6a340e827b559f24db9292fcdd354838f9339a5fa1d7f6b2087f04835828b13463dd40927866f16ae33ed501ec0e6c4e63948768c5aeea3e4f6754985954bea7d61088c44430204ef491b74a64bde1358cecb2cad28ee6a3de5b752ff6a051104d88478653339457ac45ba44cbb65f54d1969d047cda746931d5e6a8b48e211416aefd5729f3d60b56b54e7f85aa2f42de3cb69419240c24e67139a11790a709edef2ac52cf35dd0a08af45926ebe9761f498ff83bfe263d6897ee97943a4b982fe3404ef0b4a45e06113c60340e0664f14799bf59cb4b3934b465fabefd87155905ee5309ba41e9e402973311831ea600b16437f71df39ee77130490c4d0227e5d1757fdc66af3ae6b9953053ed9aafca0160209858a7d4dd38fe10e0cb153672d08633ed6c54977aa0a6e67f9ff2f8c9d22dd7b21de08192960fd0e0da68d77c8d810db11dcaa61c725cd4092cbff76c8e1debd8d0361bb3f2e607911d45716f53067bdc0d89dd4889177765166a424e9fc0cb711201099dda213355e6639ac7eb86eca2ae0ab38b7f674f37ef8a6fcca1a6f52f55d9e1dcd631d2c3c82bba129172feb991d5af51afecd9d61a88b6832e4107480e392aed61a8644f551665ebff6b20953b635737a4f895e429fddcfe801f606fbda74b3bf6f5767d0fac14907fcfd0aa1d4c11b9e91b01d68052399b51a29f1ae6acd965109977c14a555cbcbd21ad8cb9f8853506d4bc21c01e62d61d7b21be1b923be54914e6b0a7ca84dd11f1159193e1184568a6134a6bbadf5b4df986edcf2019390ae841cfaa44435e28ce877d3dae4177992fa5d4e5c005876dbe3d1e63bec7dcc0942762b48b1ecc6c1a918409a8a72812a1e245c0c67be6e729c2b49bc6ee4d24a8f63e78e75db45655c26a9a78aff36fcd67117f26b8f654dca664b9f0e30681874cb749e1a692720078856286c2560b0292cc837933423147569350955c9571bf8941ba128fd339cb4268f46b94bc6ee203eb7026813706ea51c4f24c91866fc23a724bf2501327e6ae89c29f8db315dc28d2c7c719514036367e018f4835f63fdecd71f9bdced7132b6c4f8b13c69a517026fcd3622d67cb632320d5e7308f78f4b7cea11f6291b137851dc6cd6366f2785c71c3f237f81a7658b2a8d512b61e0ad5a4710b7b124151689fcb2116063fbff7e9115fed7b93de834970b838e49f8f8ba5f1f874c354078b5810a55ae289a56da563f1da6cd80a3757d6073fa55e016e45ac6cec1f69d871c92fd0ae9670c74249045e6b464787f9504128736309fed205f8df4d90e332908581298d9c75a3fa36ab0c3c9272e62de53ab290c803d67b696fd615c260a47bffad16746f18ba1a10a061bacbea9369693b3c042eec36bed289d7d12e52bca8aa1c2dff88ca7816498d25626d0f1e106ebb0b4a12138e00f3df5b1c2f49d98b1756e69b641b7c6353d99dbff050f4d76842c6cf1c2a4b062fc8e6336fa689b7c9d5c6b4ab8c15a5c20e514ff070a602d85ae52fa7810c22f8eeffd34a095b93342144f7a98d024216b3d68ed7bea047517bfcd83ec83febd1ba0e5858e2bdc1d8b1f7b0f89e90ccc432a3f930cb8209462e64556c5054c56ca2a85f16b32eb83a10459d13516faa4d23302b7607b9bd38dab2239ac9e9440c314433fdfb3ceadab4b4f87415ed6f240e017221f3b5f7ac196cdf54957bec42fe6893994b46de3d27dc7fb58ca88feb5b9e79cf20053d12530ac524337b22a3629bea52f40b06d3e2128f32060f9105847daed81d35f20e2002817434659baff64494c5b5c7f9216bfda38412a0f70511159dc73bb6bae1f8eaa0ef08d99bcb31f94f6be12c29c83df45926430b366c99fca3270c15fc4056398fdf3135b7779e3066a006961d1ac0ad1c83179ce39e87a96b722ec23aabc065badf3e188347a360772ca6a447abac7e6a44f0d4632d52926332e44a0a86bff5ce699fd063bdda3ffd4c41b53ded49fecec67f40599b934e16e3fd1bc063ad7026f8d71bfd4cbaf56599586774723194b692036f1b6bb242e2ffb9c600b5215b412764599476ce475c9e5b396fbcebd6be323dcf4d0048077400aac7500db41dc95fc7f7edbe7c9c2ec5ea89943fe13b42217eef530bbd023671509e12dfce4e1c1c82955d965e6a68aa66f6967dba48feda572db1f099d9a6dc4bc8edade852b5e824a06890dc48a6a6510ecaf8cf7620d757290e3166d431abecc624fa9ac2234d2eb783308ead45544910c633a94964b2ef5fbc409cb8835ac4147d384e12e0a5e13951f7de0ee13eafcb0ca0c04946d7804040c0a3cd088352424b097adb7aad1ca4495952f3e6c0158c02d2bcec33bfda69301434a84d9027ce02c0b9725dad118", "d894b86261436362e64241e61f6b3e6589daf64dc641f60570c4c0bf3b1f2ca3"); } +static MuHash3072 FromInt(unsigned char i) { + unsigned char tmp[32] = {i, 0}; + return MuHash3072(tmp); +} + +BOOST_AUTO_TEST_CASE(muhash_tests) +{ + uint256 out; + + for (int iter = 0; iter < 10; ++iter) { + uint256 res; + int table[4]; + for (int i = 0; i < 4; ++i) { + table[i] = g_insecure_rand_ctx.randbits(3); + } + for (int order = 0; order < 4; ++order) { + MuHash3072 acc; + for (int i = 0; i < 4; ++i) { + int t = table[i ^ order]; + if (t & 4) { + acc /= FromInt(t & 3); + } else { + acc *= FromInt(t & 3); + } + } + acc.Finalize(out); + if (order == 0) { + res = out; + } else { + BOOST_CHECK(res == out); + } + } + + MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X + MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X, y=Y + MuHash3072 z; // x=X, y=Y, z=1 + z *= x; // x=X, y=Y, z=X + z *= y; // x=X, y=Y, z=X*Y + y *= x; // x=X, y=Y*X, z=X*Y + z /= y; // x=X, y=Y*X, z=1 + z.Finalize(out); + + uint256 out2; + MuHash3072 a; + a.Finalize(out2); + + BOOST_CHECK_EQUAL(out, out2); + } + + MuHash3072 acc = FromInt(0); + acc *= FromInt(1); + acc /= FromInt(2); + acc.Finalize(out); + BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863")); + + MuHash3072 acc2 = FromInt(0); + unsigned char tmp[32] = {1, 0}; + acc2.Insert(tmp); + unsigned char tmp2[32] = {2, 0}; + acc2.Remove(tmp2); + acc2.Finalize(out); + BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863")); + + // Test MuHash3072 serialization + MuHash3072 serchk = FromInt(1); serchk *= FromInt(2); + std::string ser_exp = "1fa093295ea30a6a3acdc7b3f770fa538eff537528e990e2910e40bbcfd7f6696b1256901929094694b56316de342f593303dd12ac43e06dce1be1ff8301c845beb15468fff0ef002dbf80c29f26e6452bccc91b5cb9437ad410d2a67ea847887fa3c6a6553309946880fe20db2c73fe0641adbd4e86edfee0d9f8cd0ee1230898873dc13ed8ddcaf045c80faa082774279007a2253f8922ee3ef361d378a6af3ddaf180b190ac97e556888c36b3d1fb1c85aab9ccd46e3deaeb7b7cf5db067a7e9ff86b658cf3acd6662bbcce37232daa753c48b794356c020090c831a8304416e2aa7ad633c0ddb2f11be1be316a81be7f7e472071c042cb68faef549c221ebff209273638b741aba5a81675c45a5fa92fea4ca821d7a324cb1e1a2ccd3b76c4228ec8066dad2a5df6e1bd0de45c7dd5de8070bdb46db6c554cf9aefc9b7b2bbf9f75b1864d9f95005314593905c0109b71f703d49944ae94477b51dac10a816bb6d1c700bafabc8bd86fac8df24be519a2f2836b16392e18036cb13e48c5c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + CDataStream ss_chk(SER_DISK, PROTOCOL_VERSION); + ss_chk << serchk; + BOOST_CHECK_EQUAL(ser_exp, HexStr(ss_chk.str())); + + // Test MuHash3072 deserialization + MuHash3072 deserchk; + ss_chk >> deserchk; + uint256 out3; + serchk.Finalize(out); + deserchk.Finalize(out3); + BOOST_CHECK_EQUAL(HexStr(out), HexStr(out3)); + + // Test MuHash3072 overflow, meaning the internal data is larger than the modulus. + CDataStream ss_max(ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), SER_DISK, PROTOCOL_VERSION); + MuHash3072 overflowchk; + ss_max >> overflowchk; + + uint256 out4; + overflowchk.Finalize(out4); + BOOST_CHECK_EQUAL(HexStr(out4), "3a31e6903aff0de9f62f9a9f7f8b861de76ce2cda09822b90014319ae5dc2271"); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 712567ac0d..cf6009d591 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -80,15 +80,15 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) { const CChainParams& chainparams = Params(); auto connman = MakeUnique<CConnman>(0x1337, 0x1337); - auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool); + auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler, + *m_node.chainman, *m_node.mempool, false); // Mock an outbound peer CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY); + CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY); dummyNode1.SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(&dummyNode1); - dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; // This test requires that we have a chain with non-zero work. @@ -130,18 +130,17 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) SetMockTime(0); bool dummy; - peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); + peerLogic->FinalizeNode(dummyNode1, dummy); } static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerManager &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(), "", ConnectionType::OUTBOUND_FULL_RELAY)); + vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY)); CNode &node = *vNodes.back(); node.SetCommonVersion(PROTOCOL_VERSION); peerLogic.InitializeNode(&node); - node.nVersion = 1; node.fSuccessfullyConnected = true; connman->AddNode(node); @@ -151,7 +150,8 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) { const CChainParams& chainparams = Params(); auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337); - auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool); + auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler, + *m_node.chainman, *m_node.mempool, false); constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS; CConnman::Options options; @@ -213,7 +213,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) bool dummy; for (const CNode *node : vNodes) { - peerLogic->FinalizeNode(node->GetId(), dummy); + peerLogic->FinalizeNode(*node, dummy); } connman->ClearNodes(); @@ -224,14 +224,14 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) const CChainParams& chainparams = Params(); auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = MakeUnique<CConnman>(0x1337, 0x1337); - auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool); + auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler, + *m_node.chainman, *m_node.mempool, false); banman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::INBOUND); + CNode dummyNode1(id++, NODE_NETWORK, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::INBOUND); dummyNode1.SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(&dummyNode1); - dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; peerLogic->Misbehaving(dummyNode1.GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ ""); // Should be discouraged { @@ -242,10 +242,9 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) BOOST_CHECK(!banman->IsDiscouraged(ip(0xa0b0c001|0x0000ff00))); // Different IP, not discouraged CAddress addr2(ip(0xa0b0c002), NODE_NONE); - CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", ConnectionType::INBOUND); + CNode dummyNode2(id++, NODE_NETWORK, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", ConnectionType::INBOUND); dummyNode2.SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(&dummyNode2); - dummyNode2.nVersion = 1; dummyNode2.fSuccessfullyConnected = true; peerLogic->Misbehaving(dummyNode2.GetId(), DISCOURAGEMENT_THRESHOLD - 1, /* message */ ""); { @@ -263,8 +262,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) BOOST_CHECK(banman->IsDiscouraged(addr2)); // to be discouraged now bool dummy; - peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); - peerLogic->FinalizeNode(dummyNode2.GetId(), dummy); + peerLogic->FinalizeNode(dummyNode1, dummy); + peerLogic->FinalizeNode(dummyNode2, dummy); } BOOST_AUTO_TEST_CASE(DoS_bantime) @@ -272,17 +271,17 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) const CChainParams& chainparams = Params(); auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto connman = MakeUnique<CConnman>(0x1337, 0x1337); - auto peerLogic = MakeUnique<PeerManager>(chainparams, *connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool); + auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler, + *m_node.chainman, *m_node.mempool, false); banman->ClearBanned(); int64_t nStartTime = GetTime(); SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", ConnectionType::INBOUND); + CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, 4, 4, CAddress(), "", ConnectionType::INBOUND); dummyNode.SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(&dummyNode); - dummyNode.nVersion = 1; dummyNode.fSuccessfullyConnected = true; peerLogic->Misbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD, /* message */ ""); @@ -293,7 +292,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) BOOST_CHECK(banman->IsDiscouraged(addr)); bool dummy; - peerLogic->FinalizeNode(dummyNode.GetId(), dummy); + peerLogic->FinalizeNode(dummyNode, dummy); } static CTransactionRef RandomOrphan() diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp index be7484cd0b..0c5c19113d 100644 --- a/src/test/flatfile_tests.cpp +++ b/src/test/flatfile_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index d02c3613ba..ec487aa3ff 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -52,6 +52,23 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); } + { + // Join an absolute path and a relative path. + fs::path p = fsbridge::AbsPathJoin(tmpfolder, "fs_tests_₿_🏃"); + BOOST_CHECK(p.is_absolute()); + BOOST_CHECK_EQUAL(tmpfile1, p); + } + { + // Join two absolute paths. + fs::path p = fsbridge::AbsPathJoin(tmpfile1, tmpfile2); + BOOST_CHECK(p.is_absolute()); + BOOST_CHECK_EQUAL(tmpfile2, p); + } + { + // Ensure joining with empty paths does not add trailing path components. + BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, "")); + BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, {})); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/fuzz/FuzzedDataProvider.h b/src/test/fuzz/FuzzedDataProvider.h index 3e069eba69..744a9d78ce 100644 --- a/src/test/fuzz/FuzzedDataProvider.h +++ b/src/test/fuzz/FuzzedDataProvider.h @@ -14,6 +14,7 @@ #define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ #include <algorithm> +#include <array> #include <climits> #include <cstddef> #include <cstdint> @@ -34,272 +35,362 @@ class FuzzedDataProvider { : data_ptr_(data), remaining_bytes_(size) {} ~FuzzedDataProvider() = default; - // Returns a std::vector containing |num_bytes| of input data. If fewer than - // |num_bytes| of data remain, returns a shorter std::vector containing all - // of the data that's left. Can be used with any byte sized type, such as - // char, unsigned char, uint8_t, etc. - template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes) { - num_bytes = std::min(num_bytes, remaining_bytes_); - return ConsumeBytes<T>(num_bytes, num_bytes); - } + // See the implementation below (after the class definition) for more verbose + // comments for each of the methods. - // Similar to |ConsumeBytes|, but also appends the terminator value at the end - // of the resulting vector. Useful, when a mutable null-terminated C-string is - // needed, for example. But that is a rare case. Better avoid it, if possible, - // and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods. + // Methods returning std::vector of bytes. These are the most popular choice + // when splitting fuzzing input into pieces, as every piece is put into a + // separate buffer (i.e. ASan would catch any under-/overflow) and the memory + // will be released automatically. + template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes); template <typename T> - std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, - T terminator = 0) { - num_bytes = std::min(num_bytes, remaining_bytes_); - std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes); - result.back() = terminator; - return result; - } + std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0); + template <typename T> std::vector<T> ConsumeRemainingBytes(); - // Returns a std::string containing |num_bytes| of input data. Using this and - // |.c_str()| on the resulting string is the best way to get an immutable - // null-terminated C string. If fewer than |num_bytes| of data remain, returns - // a shorter std::string containing all of the data that's left. - std::string ConsumeBytesAsString(size_t num_bytes) { - static_assert(sizeof(std::string::value_type) == sizeof(uint8_t), - "ConsumeBytesAsString cannot convert the data to a string."); - - num_bytes = std::min(num_bytes, remaining_bytes_); - std::string result( - reinterpret_cast<const std::string::value_type *>(data_ptr_), - num_bytes); - Advance(num_bytes); - return result; - } + // Methods returning strings. Use only when you need a std::string or a null + // terminated C-string. Otherwise, prefer the methods returning std::vector. + std::string ConsumeBytesAsString(size_t num_bytes); + std::string ConsumeRandomLengthString(size_t max_length); + std::string ConsumeRandomLengthString(); + std::string ConsumeRemainingBytesAsString(); - // Returns a number in the range [min, max] by consuming bytes from the - // input data. The value might not be uniformly distributed in the given - // range. If there's no input data left, always returns |min|. |min| must - // be less than or equal to |max|. - template <typename T> T ConsumeIntegralInRange(T min, T max) { - static_assert(std::is_integral<T>::value, "An integral type is required."); - static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type."); + // Methods returning integer values. + template <typename T> T ConsumeIntegral(); + template <typename T> T ConsumeIntegralInRange(T min, T max); - if (min > max) - abort(); + // Methods returning floating point values. + template <typename T> T ConsumeFloatingPoint(); + template <typename T> T ConsumeFloatingPointInRange(T min, T max); - // Use the biggest type possible to hold the range and the result. - uint64_t range = static_cast<uint64_t>(max) - min; - uint64_t result = 0; - size_t offset = 0; - - while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && - remaining_bytes_ != 0) { - // Pull bytes off the end of the seed data. Experimentally, this seems to - // allow the fuzzer to more easily explore the input space. This makes - // sense, since it works by modifying inputs that caused new code to run, - // and this data is often used to encode length of data read by - // |ConsumeBytes|. Separating out read lengths makes it easier modify the - // contents of the data that is actually read. - --remaining_bytes_; - result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_]; - offset += CHAR_BIT; - } + // 0 <= return value <= 1. + template <typename T> T ConsumeProbability(); - // Avoid division by 0, in case |range + 1| results in overflow. - if (range != std::numeric_limits<decltype(range)>::max()) - result = result % (range + 1); + bool ConsumeBool(); - return static_cast<T>(min + result); - } + // Returns a value chosen from the given enum. + template <typename T> T ConsumeEnum(); - // Returns a std::string of length from 0 to |max_length|. When it runs out of - // input data, returns what remains of the input. Designed to be more stable - // with respect to a fuzzer inserting characters than just picking a random - // length and then consuming that many bytes with |ConsumeBytes|. - std::string ConsumeRandomLengthString(size_t max_length) { - // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\" - // followed by anything else to the end of the string. As a result of this - // logic, a fuzzer can insert characters into the string, and the string - // will be lengthened to include those new characters, resulting in a more - // stable fuzzer than picking the length of a string independently from - // picking its contents. - std::string result; - - // Reserve the anticipated capaticity to prevent several reallocations. - result.reserve(std::min(max_length, remaining_bytes_)); - for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) { - char next = ConvertUnsignedToSigned<char>(data_ptr_[0]); - Advance(1); - if (next == '\\' && remaining_bytes_ != 0) { - next = ConvertUnsignedToSigned<char>(data_ptr_[0]); - Advance(1); - if (next != '\\') - break; - } - result += next; - } - - result.shrink_to_fit(); - return result; - } + // Returns a value from the given array. + template <typename T, size_t size> T PickValueInArray(const T (&array)[size]); + template <typename T, size_t size> + T PickValueInArray(const std::array<T, size> &array); + template <typename T> T PickValueInArray(std::initializer_list<const T> list); - // Returns a std::vector containing all remaining bytes of the input data. - template <typename T> std::vector<T> ConsumeRemainingBytes() { - return ConsumeBytes<T>(remaining_bytes_); - } + // Writes data to the given destination and returns number of bytes written. + size_t ConsumeData(void *destination, size_t num_bytes); - // Returns a std::string containing all remaining bytes of the input data. - // Prefer using |ConsumeRemainingBytes| unless you actually need a std::string - // object. - std::string ConsumeRemainingBytesAsString() { - return ConsumeBytesAsString(remaining_bytes_); - } + // Reports the remaining bytes available for fuzzed input. + size_t remaining_bytes() { return remaining_bytes_; } - // Returns a number in the range [Type's min, Type's max]. The value might - // not be uniformly distributed in the given range. If there's no input data - // left, always returns |min|. - template <typename T> T ConsumeIntegral() { - return ConsumeIntegralInRange(std::numeric_limits<T>::min(), - std::numeric_limits<T>::max()); - } + private: + FuzzedDataProvider(const FuzzedDataProvider &) = delete; + FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete; - // Reads one byte and returns a bool, or false when no data remains. - bool ConsumeBool() { return 1 & ConsumeIntegral<uint8_t>(); } + void CopyAndAdvance(void *destination, size_t num_bytes); - // Returns a copy of the value selected from the given fixed-size |array|. - template <typename T, size_t size> - T PickValueInArray(const T (&array)[size]) { - static_assert(size > 0, "The array must be non empty."); - return array[ConsumeIntegralInRange<size_t>(0, size - 1)]; - } + void Advance(size_t num_bytes); template <typename T> - T PickValueInArray(std::initializer_list<const T> list) { - // TODO(Dor1s): switch to static_assert once C++14 is allowed. - if (!list.size()) - abort(); - - return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1)); - } - - // Returns an enum value. The enum must start at 0 and be contiguous. It must - // also contain |kMaxValue| aliased to its largest (inclusive) value. Such as: - // enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue }; - template <typename T> T ConsumeEnum() { - static_assert(std::is_enum<T>::value, "|T| must be an enum type."); - return static_cast<T>(ConsumeIntegralInRange<uint32_t>( - 0, static_cast<uint32_t>(T::kMaxValue))); - } + std::vector<T> ConsumeBytes(size_t size, size_t num_bytes); - // Returns a floating point number in the range [0.0, 1.0]. If there's no - // input data left, always returns 0. - template <typename T> T ConsumeProbability() { - static_assert(std::is_floating_point<T>::value, - "A floating point type is required."); + template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value); - // Use different integral types for different floating point types in order - // to provide better density of the resulting values. - using IntegralType = - typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t, - uint64_t>::type; + const uint8_t *data_ptr_; + size_t remaining_bytes_; +}; - T result = static_cast<T>(ConsumeIntegral<IntegralType>()); - result /= static_cast<T>(std::numeric_limits<IntegralType>::max()); - return result; +// Returns a std::vector containing |num_bytes| of input data. If fewer than +// |num_bytes| of data remain, returns a shorter std::vector containing all +// of the data that's left. Can be used with any byte sized type, such as +// char, unsigned char, uint8_t, etc. +template <typename T> +std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) { + num_bytes = std::min(num_bytes, remaining_bytes_); + return ConsumeBytes<T>(num_bytes, num_bytes); +} + +// Similar to |ConsumeBytes|, but also appends the terminator value at the end +// of the resulting vector. Useful, when a mutable null-terminated C-string is +// needed, for example. But that is a rare case. Better avoid it, if possible, +// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods. +template <typename T> +std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes, + T terminator) { + num_bytes = std::min(num_bytes, remaining_bytes_); + std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes); + result.back() = terminator; + return result; +} + +// Returns a std::vector containing all remaining bytes of the input data. +template <typename T> +std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() { + return ConsumeBytes<T>(remaining_bytes_); +} + +// Returns a std::string containing |num_bytes| of input data. Using this and +// |.c_str()| on the resulting string is the best way to get an immutable +// null-terminated C string. If fewer than |num_bytes| of data remain, returns +// a shorter std::string containing all of the data that's left. +inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) { + static_assert(sizeof(std::string::value_type) == sizeof(uint8_t), + "ConsumeBytesAsString cannot convert the data to a string."); + + num_bytes = std::min(num_bytes, remaining_bytes_); + std::string result( + reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes); + Advance(num_bytes); + return result; +} + +// Returns a std::string of length from 0 to |max_length|. When it runs out of +// input data, returns what remains of the input. Designed to be more stable +// with respect to a fuzzer inserting characters than just picking a random +// length and then consuming that many bytes with |ConsumeBytes|. +inline std::string +FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) { + // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\" + // followed by anything else to the end of the string. As a result of this + // logic, a fuzzer can insert characters into the string, and the string + // will be lengthened to include those new characters, resulting in a more + // stable fuzzer than picking the length of a string independently from + // picking its contents. + std::string result; + + // Reserve the anticipated capaticity to prevent several reallocations. + result.reserve(std::min(max_length, remaining_bytes_)); + for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) { + char next = ConvertUnsignedToSigned<char>(data_ptr_[0]); + Advance(1); + if (next == '\\' && remaining_bytes_ != 0) { + next = ConvertUnsignedToSigned<char>(data_ptr_[0]); + Advance(1); + if (next != '\\') + break; + } + result += next; } - // Returns a floating point value in the range [Type's lowest, Type's max] by - // consuming bytes from the input data. If there's no input data left, always - // returns approximately 0. - template <typename T> T ConsumeFloatingPoint() { - return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(), - std::numeric_limits<T>::max()); + result.shrink_to_fit(); + return result; +} + +// Returns a std::string of length from 0 to |remaining_bytes_|. +inline std::string FuzzedDataProvider::ConsumeRandomLengthString() { + return ConsumeRandomLengthString(remaining_bytes_); +} + +// Returns a std::string containing all remaining bytes of the input data. +// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string +// object. +inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() { + return ConsumeBytesAsString(remaining_bytes_); +} + +// Returns a number in the range [Type's min, Type's max]. The value might +// not be uniformly distributed in the given range. If there's no input data +// left, always returns |min|. +template <typename T> T FuzzedDataProvider::ConsumeIntegral() { + return ConsumeIntegralInRange(std::numeric_limits<T>::min(), + std::numeric_limits<T>::max()); +} + +// Returns a number in the range [min, max] by consuming bytes from the +// input data. The value might not be uniformly distributed in the given +// range. If there's no input data left, always returns |min|. |min| must +// be less than or equal to |max|. +template <typename T> +T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) { + static_assert(std::is_integral<T>::value, "An integral type is required."); + static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type."); + + if (min > max) + abort(); + + // Use the biggest type possible to hold the range and the result. + uint64_t range = static_cast<uint64_t>(max) - min; + uint64_t result = 0; + size_t offset = 0; + + while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && + remaining_bytes_ != 0) { + // Pull bytes off the end of the seed data. Experimentally, this seems to + // allow the fuzzer to more easily explore the input space. This makes + // sense, since it works by modifying inputs that caused new code to run, + // and this data is often used to encode length of data read by + // |ConsumeBytes|. Separating out read lengths makes it easier modify the + // contents of the data that is actually read. + --remaining_bytes_; + result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_]; + offset += CHAR_BIT; } - // Returns a floating point value in the given range by consuming bytes from - // the input data. If there's no input data left, returns |min|. Note that - // |min| must be less than or equal to |max|. - template <typename T> T ConsumeFloatingPointInRange(T min, T max) { - if (min > max) - abort(); - - T range = .0; - T result = min; - constexpr T zero(.0); - if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) { - // The diff |max - min| would overflow the given floating point type. Use - // the half of the diff as the range and consume a bool to decide whether - // the result is in the first of the second part of the diff. - range = (max / 2.0) - (min / 2.0); - if (ConsumeBool()) { - result += range; - } - } else { - range = max - min; + // Avoid division by 0, in case |range + 1| results in overflow. + if (range != std::numeric_limits<decltype(range)>::max()) + result = result % (range + 1); + + return static_cast<T>(min + result); +} + +// Returns a floating point value in the range [Type's lowest, Type's max] by +// consuming bytes from the input data. If there's no input data left, always +// returns approximately 0. +template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() { + return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(), + std::numeric_limits<T>::max()); +} + +// Returns a floating point value in the given range by consuming bytes from +// the input data. If there's no input data left, returns |min|. Note that +// |min| must be less than or equal to |max|. +template <typename T> +T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) { + if (min > max) + abort(); + + T range = .0; + T result = min; + constexpr T zero(.0); + if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) { + // The diff |max - min| would overflow the given floating point type. Use + // the half of the diff as the range and consume a bool to decide whether + // the result is in the first of the second part of the diff. + range = (max / 2.0) - (min / 2.0); + if (ConsumeBool()) { + result += range; } - - return result + range * ConsumeProbability<T>(); + } else { + range = max - min; } - // Reports the remaining bytes available for fuzzed input. - size_t remaining_bytes() { return remaining_bytes_; } - - private: - FuzzedDataProvider(const FuzzedDataProvider &) = delete; - FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete; - - void Advance(size_t num_bytes) { - if (num_bytes > remaining_bytes_) + return result + range * ConsumeProbability<T>(); +} + +// Returns a floating point number in the range [0.0, 1.0]. If there's no +// input data left, always returns 0. +template <typename T> T FuzzedDataProvider::ConsumeProbability() { + static_assert(std::is_floating_point<T>::value, + "A floating point type is required."); + + // Use different integral types for different floating point types in order + // to provide better density of the resulting values. + using IntegralType = + typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t, + uint64_t>::type; + + T result = static_cast<T>(ConsumeIntegral<IntegralType>()); + result /= static_cast<T>(std::numeric_limits<IntegralType>::max()); + return result; +} + +// Reads one byte and returns a bool, or false when no data remains. +inline bool FuzzedDataProvider::ConsumeBool() { + return 1 & ConsumeIntegral<uint8_t>(); +} + +// Returns an enum value. The enum must start at 0 and be contiguous. It must +// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as: +// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue }; +template <typename T> T FuzzedDataProvider::ConsumeEnum() { + static_assert(std::is_enum<T>::value, "|T| must be an enum type."); + return static_cast<T>( + ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue))); +} + +// Returns a copy of the value selected from the given fixed-size |array|. +template <typename T, size_t size> +T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) { + static_assert(size > 0, "The array must be non empty."); + return array[ConsumeIntegralInRange<size_t>(0, size - 1)]; +} + +template <typename T, size_t size> +T FuzzedDataProvider::PickValueInArray(const std::array<T, size> &array) { + static_assert(size > 0, "The array must be non empty."); + return array[ConsumeIntegralInRange<size_t>(0, size - 1)]; +} + +template <typename T> +T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) { + // TODO(Dor1s): switch to static_assert once C++14 is allowed. + if (!list.size()) + abort(); + + return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1)); +} + +// Writes |num_bytes| of input data to the given destination pointer. If there +// is not enough data left, writes all remaining bytes. Return value is the +// number of bytes written. +// In general, it's better to avoid using this function, but it may be useful +// in cases when it's necessary to fill a certain buffer or object with +// fuzzing data. +inline size_t FuzzedDataProvider::ConsumeData(void *destination, + size_t num_bytes) { + num_bytes = std::min(num_bytes, remaining_bytes_); + CopyAndAdvance(destination, num_bytes); + return num_bytes; +} + +// Private methods. +inline void FuzzedDataProvider::CopyAndAdvance(void *destination, + size_t num_bytes) { + std::memcpy(destination, data_ptr_, num_bytes); + Advance(num_bytes); +} + +inline void FuzzedDataProvider::Advance(size_t num_bytes) { + if (num_bytes > remaining_bytes_) + abort(); + + data_ptr_ += num_bytes; + remaining_bytes_ -= num_bytes; +} + +template <typename T> +std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) { + static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type."); + + // The point of using the size-based constructor below is to increase the + // odds of having a vector object with capacity being equal to the length. + // That part is always implementation specific, but at least both libc++ and + // libstdc++ allocate the requested number of bytes in that constructor, + // which seems to be a natural choice for other implementations as well. + // To increase the odds even more, we also call |shrink_to_fit| below. + std::vector<T> result(size); + if (size == 0) { + if (num_bytes != 0) abort(); - - data_ptr_ += num_bytes; - remaining_bytes_ -= num_bytes; - } - - template <typename T> - std::vector<T> ConsumeBytes(size_t size, size_t num_bytes_to_consume) { - static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type."); - - // The point of using the size-based constructor below is to increase the - // odds of having a vector object with capacity being equal to the length. - // That part is always implementation specific, but at least both libc++ and - // libstdc++ allocate the requested number of bytes in that constructor, - // which seems to be a natural choice for other implementations as well. - // To increase the odds even more, we also call |shrink_to_fit| below. - std::vector<T> result(size); - if (size == 0) { - if (num_bytes_to_consume != 0) - abort(); - return result; - } - - std::memcpy(result.data(), data_ptr_, num_bytes_to_consume); - Advance(num_bytes_to_consume); - - // Even though |shrink_to_fit| is also implementation specific, we expect it - // to provide an additional assurance in case vector's constructor allocated - // a buffer which is larger than the actual amount of data we put inside it. - result.shrink_to_fit(); return result; } - template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value) { - static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types."); - static_assert(!std::numeric_limits<TU>::is_signed, - "Source type must be unsigned."); - - // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream. - if (std::numeric_limits<TS>::is_modulo) - return static_cast<TS>(value); - - // Avoid using implementation-defined unsigned to signer conversions. - // To learn more, see https://stackoverflow.com/questions/13150449. - if (value <= std::numeric_limits<TS>::max()) { - return static_cast<TS>(value); - } else { - constexpr auto TS_min = std::numeric_limits<TS>::min(); - return TS_min + static_cast<char>(value - TS_min); - } + CopyAndAdvance(result.data(), num_bytes); + + // Even though |shrink_to_fit| is also implementation specific, we expect it + // to provide an additional assurance in case vector's constructor allocated + // a buffer which is larger than the actual amount of data we put inside it. + result.shrink_to_fit(); + return result; +} + +template <typename TS, typename TU> +TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) { + static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types."); + static_assert(!std::numeric_limits<TU>::is_signed, + "Source type must be unsigned."); + + // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream. + if (std::numeric_limits<TS>::is_modulo) + return static_cast<TS>(value); + + // Avoid using implementation-defined unsigned to signed conversions. + // To learn more, see https://stackoverflow.com/questions/13150449. + if (value <= std::numeric_limits<TS>::max()) { + return static_cast<TS>(value); + } else { + constexpr auto TS_min = std::numeric_limits<TS>::min(); + return TS_min + static_cast<char>(value - TS_min); } - - const uint8_t *data_ptr_; - size_t remaining_bytes_; -}; +} #endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_ diff --git a/src/test/fuzz/addition_overflow.cpp b/src/test/fuzz/addition_overflow.cpp index a455992b13..c6cfbd8d30 100644 --- a/src/test/fuzz/addition_overflow.cpp +++ b/src/test/fuzz/addition_overflow.cpp @@ -14,7 +14,7 @@ #if __has_builtin(__builtin_add_overflow) #define HAVE_BUILTIN_ADD_OVERFLOW #endif -#elif defined(__GNUC__) && (__GNUC__ >= 5) +#elif defined(__GNUC__) #define HAVE_BUILTIN_ADD_OVERFLOW #endif @@ -40,7 +40,7 @@ void TestAdditionOverflow(FuzzedDataProvider& fuzzed_data_provider) } } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(addition_overflow) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); TestAdditionOverflow<int64_t>(fuzzed_data_provider); diff --git a/src/test/fuzz/addrdb.cpp b/src/test/fuzz/addrdb.cpp index 16b1cb755a..d15c785673 100644 --- a/src/test/fuzz/addrdb.cpp +++ b/src/test/fuzz/addrdb.cpp @@ -13,7 +13,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(addrdb) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp new file mode 100644 index 0000000000..1ea6b3d01d --- /dev/null +++ b/src/test/fuzz/addrman.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <addrdb.h> +#include <addrman.h> +#include <chainparams.h> +#include <merkleblock.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <time.h> +#include <util/asmap.h> + +#include <cstdint> +#include <optional> +#include <string> +#include <vector> + +void initialize_addrman() +{ + SelectParams(CBaseChainParams::REGTEST); +} + +class CAddrManDeterministic : public CAddrMan +{ +public: + void MakeDeterministic(const uint256& random_seed) + { + insecure_rand = FastRandomContext{random_seed}; + Clear(); + } +}; + +FUZZ_TARGET_INIT(addrman, initialize_addrman) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + SetMockTime(ConsumeTime(fuzzed_data_provider)); + CAddrManDeterministic addr_man; + addr_man.MakeDeterministic(ConsumeUInt256(fuzzed_data_provider)); + if (fuzzed_data_provider.ConsumeBool()) { + addr_man.m_asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); + if (!SanityCheckASMap(addr_man.m_asmap)) { + addr_man.m_asmap.clear(); + } + } + while (fuzzed_data_provider.ConsumeBool()) { + CallOneOf( + fuzzed_data_provider, + [&] { + addr_man.Clear(); + }, + [&] { + addr_man.ResolveCollisions(); + }, + [&] { + (void)addr_man.SelectTriedCollision(); + }, + [&] { + (void)addr_man.Select(fuzzed_data_provider.ConsumeBool()); + }, + [&] { + (void)addr_man.GetAddr(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + }, + [&] { + const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider); + if (opt_address && opt_net_addr) { + addr_man.Add(*opt_address, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000)); + } + }, + [&] { + std::vector<CAddress> addresses; + while (fuzzed_data_provider.ConsumeBool()) { + const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + if (!opt_address) { + break; + } + addresses.push_back(*opt_address); + } + const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider); + if (opt_net_addr) { + addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000)); + } + }, + [&] { + const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); + if (opt_service) { + addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); + } + }, + [&] { + const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); + if (opt_service) { + addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); + } + }, + [&] { + const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); + if (opt_service) { + addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider)); + } + }, + [&] { + const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); + if (opt_service) { + addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral<uint64_t>()}); + } + }, + [&] { + (void)addr_man.Check(); + }); + } + (void)addr_man.size(); + CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION); + data_stream << addr_man; +} diff --git a/src/test/fuzz/asmap.cpp b/src/test/fuzz/asmap.cpp index e3aefa18a3..4c5bc0cbf2 100644 --- a/src/test/fuzz/asmap.cpp +++ b/src/test/fuzz/asmap.cpp @@ -27,7 +27,7 @@ static const std::vector<bool> IPV4_PREFIX_ASMAP = { true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true // Match 0xFF }; -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(asmap) { // Encoding: [7 bits: asmap size] [1 bit: ipv6?] [3-130 bytes: asmap] [4 or 16 bytes: addr] if (buffer.size() < 1 + 3 + 4) return; diff --git a/src/test/fuzz/asmap_direct.cpp b/src/test/fuzz/asmap_direct.cpp index 2d21eff9d6..8b7822dc16 100644 --- a/src/test/fuzz/asmap_direct.cpp +++ b/src/test/fuzz/asmap_direct.cpp @@ -11,7 +11,7 @@ #include <assert.h> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(asmap_direct) { // Encoding: [asmap using 1 bit / byte] 0xFF [addr using 1 bit / byte] std::optional<size_t> sep_pos_opt; diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp index 7ea0bdd2a7..9ecd172e19 100644 --- a/src/test/fuzz/autofile.cpp +++ b/src/test/fuzz/autofile.cpp @@ -15,49 +15,43 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(autofile) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider); CAutoFile auto_file = fuzzed_auto_file_provider.open(); while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) { - case 0: { - std::array<uint8_t, 4096> arr{}; - try { - auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 1: { - const std::array<uint8_t, 4096> arr{}; - try { - auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 2: { - try { - auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 3: { - auto_file.fclose(); - break; - } - case 4: { - ReadFromStream(fuzzed_data_provider, auto_file); - break; - } - case 5: { - WriteToStream(fuzzed_data_provider, auto_file); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + std::array<uint8_t, 4096> arr{}; + try { + auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + const std::array<uint8_t, 4096> arr{}; + try { + auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + try { + auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + auto_file.fclose(); + }, + [&] { + ReadFromStream(fuzzed_data_provider, auto_file); + }, + [&] { + WriteToStream(fuzzed_data_provider, auto_file); + }); } (void)auto_file.Get(); (void)auto_file.GetType(); diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp index fc4a1d9261..e0715f3e29 100644 --- a/src/test/fuzz/banman.cpp +++ b/src/test/fuzz/banman.cpp @@ -24,64 +24,57 @@ int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept } } // namespace -void initialize() +void initialize_banman() { - InitializeFuzzingContext(); + static const auto testing_setup = MakeFuzzingContext<>(); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(banman, initialize_banman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + SetMockTime(ConsumeTime(fuzzed_data_provider)); const fs::path banlist_file = GetDataDir() / "fuzzed_banlist.dat"; fs::remove(banlist_file); { BanMan ban_man{banlist_file, nullptr, ConsumeBanTimeOffset(fuzzed_data_provider)}; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) { - case 0: { - ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider), - ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); - break; - } - case 1: { - ban_man.Ban(ConsumeSubNet(fuzzed_data_provider), - ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); - break; - } - case 2: { - ban_man.ClearBanned(); - break; - } - case 4: { - ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider)); - break; - } - case 5: { - ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider)); - break; - } - case 6: { - ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider)); - break; - } - case 7: { - ban_man.Unban(ConsumeSubNet(fuzzed_data_provider)); - break; - } - case 8: { - banmap_t banmap; - ban_man.GetBanned(banmap); - break; - } - case 9: { - ban_man.DumpBanlist(); - break; - } - case 11: { - ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider)); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider), + ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); + }, + [&] { + ban_man.Ban(ConsumeSubNet(fuzzed_data_provider), + ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool()); + }, + [&] { + ban_man.ClearBanned(); + }, + [] {}, + [&] { + ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider)); + }, + [&] { + ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider)); + }, + [&] { + ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider)); + }, + [&] { + ban_man.Unban(ConsumeSubNet(fuzzed_data_provider)); + }, + [&] { + banmap_t banmap; + ban_man.GetBanned(banmap); + }, + [&] { + ban_man.DumpBanlist(); + }, + [] {}, + [&] { + ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider)); + }); } } fs::remove(banlist_file); diff --git a/src/test/fuzz/base_encode_decode.cpp b/src/test/fuzz/base_encode_decode.cpp index 8d49f93c2f..4470e13a61 100644 --- a/src/test/fuzz/base_encode_decode.cpp +++ b/src/test/fuzz/base_encode_decode.cpp @@ -14,7 +14,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(base_encode_decode) { const std::string random_encoded_string(buffer.begin(), buffer.end()); diff --git a/src/test/fuzz/bech32.cpp b/src/test/fuzz/bech32.cpp index 8b91f9bc96..95cd4b413f 100644 --- a/src/test/fuzz/bech32.cpp +++ b/src/test/fuzz/bech32.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,7 +13,7 @@ #include <utility> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(bech32) { const std::string random_string(buffer.begin(), buffer.end()); const std::pair<std::string, std::vector<uint8_t>> r1 = bech32::Decode(random_string); diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp index 91bd34a251..65a33de4b4 100644 --- a/src/test/fuzz/block.cpp +++ b/src/test/fuzz/block.cpp @@ -17,13 +17,13 @@ #include <cassert> #include <string> -void initialize() +void initialize_block() { static const ECCVerifyHandle verify_handle; SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(block, initialize_block) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); CBlock block; diff --git a/src/test/fuzz/block_header.cpp b/src/test/fuzz/block_header.cpp index 09c2b4a951..c73270dcb3 100644 --- a/src/test/fuzz/block_header.cpp +++ b/src/test/fuzz/block_header.cpp @@ -14,7 +14,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(block_header) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::optional<CBlockHeader> block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider); diff --git a/src/test/fuzz/blockfilter.cpp b/src/test/fuzz/blockfilter.cpp index 7232325a20..7fa06085f8 100644 --- a/src/test/fuzz/blockfilter.cpp +++ b/src/test/fuzz/blockfilter.cpp @@ -12,7 +12,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(blockfilter) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::optional<BlockFilter> block_filter = ConsumeDeserializable<BlockFilter>(fuzzed_data_provider); diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp index d955c71bc9..d43c182644 100644 --- a/src/test/fuzz/bloom_filter.cpp +++ b/src/test/fuzz/bloom_filter.cpp @@ -15,7 +15,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(bloom_filter) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); @@ -25,47 +25,43 @@ void test_one_input(const std::vector<uint8_t>& buffer) fuzzed_data_provider.ConsumeIntegral<unsigned int>(), static_cast<unsigned char>(fuzzed_data_provider.PickValueInArray({BLOOM_UPDATE_NONE, BLOOM_UPDATE_ALL, BLOOM_UPDATE_P2PUBKEY_ONLY, BLOOM_UPDATE_MASK}))}; while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 3)) { - case 0: { - const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); - (void)bloom_filter.contains(b); - bloom_filter.insert(b); - const bool present = bloom_filter.contains(b); - assert(present); - break; - } - case 1: { - const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider); - if (!out_point) { - break; - } - (void)bloom_filter.contains(*out_point); - bloom_filter.insert(*out_point); - const bool present = bloom_filter.contains(*out_point); - assert(present); - break; - } - case 2: { - const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider); - if (!u256) { - break; - } - (void)bloom_filter.contains(*u256); - bloom_filter.insert(*u256); - const bool present = bloom_filter.contains(*u256); - assert(present); - break; - } - case 3: { - const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); - if (!mut_tx) { - break; - } - const CTransaction tx{*mut_tx}; - (void)bloom_filter.IsRelevantAndUpdate(tx); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + (void)bloom_filter.contains(b); + bloom_filter.insert(b); + const bool present = bloom_filter.contains(b); + assert(present); + }, + [&] { + const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider); + if (!out_point) { + return; + } + (void)bloom_filter.contains(*out_point); + bloom_filter.insert(*out_point); + const bool present = bloom_filter.contains(*out_point); + assert(present); + }, + [&] { + const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider); + if (!u256) { + return; + } + (void)bloom_filter.contains(*u256); + bloom_filter.insert(*u256); + const bool present = bloom_filter.contains(*u256); + assert(present); + }, + [&] { + const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!mut_tx) { + return; + } + const CTransaction tx{*mut_tx}; + (void)bloom_filter.IsRelevantAndUpdate(tx); + }); (void)bloom_filter.IsWithinSizeConstraints(); } } diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp index e575640be5..3a1b2dbbe7 100644 --- a/src/test/fuzz/buffered_file.cpp +++ b/src/test/fuzz/buffered_file.cpp @@ -15,7 +15,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(buffered_file) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider); @@ -31,41 +31,36 @@ void test_one_input(const std::vector<uint8_t>& buffer) if (opt_buffered_file && fuzzed_file != nullptr) { bool setpos_fail = false; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 4)) { - case 0: { - std::array<uint8_t, 4096> arr{}; - try { - opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); - } catch (const std::ios_base::failure&) { - } - break; - } - case 1: { - opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096)); - break; - } - case 2: { - if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) { - setpos_fail = true; - } - break; - } - case 3: { - if (setpos_fail) { - // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop. - break; - } - try { - opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>()); - } catch (const std::ios_base::failure&) { - } - break; - } - case 4: { - ReadFromStream(fuzzed_data_provider, *opt_buffered_file); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + std::array<uint8_t, 4096> arr{}; + try { + opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096)); + }, + [&] { + if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) { + setpos_fail = true; + } + }, + [&] { + if (setpos_fail) { + // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop. + return; + } + try { + opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>()); + } catch (const std::ios_base::failure&) { + } + }, + [&] { + ReadFromStream(fuzzed_data_provider, *opt_buffered_file); + }); } opt_buffered_file->GetPos(); opt_buffered_file->GetType(); diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp index 47c71850ce..9f7074b423 100644 --- a/src/test/fuzz/chain.cpp +++ b/src/test/fuzz/chain.cpp @@ -11,7 +11,7 @@ #include <optional> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(chain) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); std::optional<CDiskBlockIndex> disk_block_index = ConsumeDeserializable<CDiskBlockIndex>(fuzzed_data_provider); diff --git a/src/test/fuzz/checkqueue.cpp b/src/test/fuzz/checkqueue.cpp index c69043bb6b..0b16f0f0d5 100644 --- a/src/test/fuzz/checkqueue.cpp +++ b/src/test/fuzz/checkqueue.cpp @@ -32,7 +32,7 @@ struct DumbCheck { }; } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(checkqueue) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index c186bef7ae..8ece94d771 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -34,14 +34,12 @@ bool operator==(const Coin& a, const Coin& b) } } // namespace -void initialize() +void initialize_coins_view() { - static const ECCVerifyHandle ecc_verify_handle; - ECC_Start(); - SelectParams(CBaseChainParams::REGTEST); + static const auto testing_setup = MakeFuzzingContext<const TestingSetup>(); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(coins_view, initialize_coins_view) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; CCoinsView backend_coins_view; @@ -50,103 +48,93 @@ void test_one_input(const std::vector<uint8_t>& buffer) Coin random_coin; CMutableTransaction random_mutable_transaction; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 9)) { - case 0: { - if (random_coin.IsSpent()) { - break; - } - Coin coin = random_coin; - bool expected_code_path = false; - const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); - try { - coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite); - expected_code_path = true; - } catch (const std::logic_error& e) { - if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { - assert(!possible_overwrite); + CallOneOf( + fuzzed_data_provider, + [&] { + if (random_coin.IsSpent()) { + return; + } + Coin coin = random_coin; + bool expected_code_path = false; + const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); + try { + coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite); expected_code_path = true; + } catch (const std::logic_error& e) { + if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { + assert(!possible_overwrite); + expected_code_path = true; + } } - } - assert(expected_code_path); - break; - } - case 1: { - (void)coins_view_cache.Flush(); - break; - } - case 2: { - coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider)); - break; - } - case 3: { - Coin move_to; - (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr); - break; - } - case 4: { - coins_view_cache.Uncache(random_out_point); - break; - } - case 5: { - if (fuzzed_data_provider.ConsumeBool()) { - backend_coins_view = CCoinsView{}; - } - coins_view_cache.SetBackend(backend_coins_view); - break; - } - case 6: { - const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider); - if (!opt_out_point) { - break; - } - random_out_point = *opt_out_point; - break; - } - case 7: { - const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider); - if (!opt_coin) { - break; - } - random_coin = *opt_coin; - break; - } - case 8: { - const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); - if (!opt_mutable_transaction) { - break; - } - random_mutable_transaction = *opt_mutable_transaction; - break; - } - case 9: { - CCoinsMap coins_map; - while (fuzzed_data_provider.ConsumeBool()) { - CCoinsCacheEntry coins_cache_entry; - coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>(); + assert(expected_code_path); + }, + [&] { + (void)coins_view_cache.Flush(); + }, + [&] { + coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider)); + }, + [&] { + Coin move_to; + (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr); + }, + [&] { + coins_view_cache.Uncache(random_out_point); + }, + [&] { if (fuzzed_data_provider.ConsumeBool()) { - coins_cache_entry.coin = random_coin; - } else { - const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider); - if (!opt_coin) { - break; + backend_coins_view = CCoinsView{}; + } + coins_view_cache.SetBackend(backend_coins_view); + }, + [&] { + const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider); + if (!opt_out_point) { + return; + } + random_out_point = *opt_out_point; + }, + [&] { + const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider); + if (!opt_coin) { + return; + } + random_coin = *opt_coin; + }, + [&] { + const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!opt_mutable_transaction) { + return; + } + random_mutable_transaction = *opt_mutable_transaction; + }, + [&] { + CCoinsMap coins_map; + while (fuzzed_data_provider.ConsumeBool()) { + CCoinsCacheEntry coins_cache_entry; + coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>(); + if (fuzzed_data_provider.ConsumeBool()) { + coins_cache_entry.coin = random_coin; + } else { + const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider); + if (!opt_coin) { + return; + } + coins_cache_entry.coin = *opt_coin; } - coins_cache_entry.coin = *opt_coin; + coins_map.emplace(random_out_point, std::move(coins_cache_entry)); } - coins_map.emplace(random_out_point, std::move(coins_cache_entry)); - } - bool expected_code_path = false; - try { - coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock()); - expected_code_path = true; - } catch (const std::logic_error& e) { - if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) { + bool expected_code_path = false; + try { + coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock()); expected_code_path = true; + } catch (const std::logic_error& e) { + if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) { + expected_code_path = true; + } } - } - assert(expected_code_path); - break; - } - } + assert(expected_code_path); + }); } { @@ -199,96 +187,90 @@ void test_one_input(const std::vector<uint8_t>& buffer) } if (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 6)) { - case 0: { - const CTransaction transaction{random_mutable_transaction}; - bool is_spent = false; - for (const CTxOut& tx_out : transaction.vout) { - if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) { - is_spent = true; + CallOneOf( + fuzzed_data_provider, + [&] { + const CTransaction transaction{random_mutable_transaction}; + bool is_spent = false; + for (const CTxOut& tx_out : transaction.vout) { + if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) { + is_spent = true; + } + } + if (is_spent) { + // Avoid: + // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed. + return; } - } - if (is_spent) { - // Avoid: - // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed. - break; - } - bool expected_code_path = false; - const int height = fuzzed_data_provider.ConsumeIntegral<int>(); - const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); - try { - AddCoins(coins_view_cache, transaction, height, possible_overwrite); - expected_code_path = true; - } catch (const std::logic_error& e) { - if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { - assert(!possible_overwrite); + bool expected_code_path = false; + const int height = fuzzed_data_provider.ConsumeIntegral<int>(); + const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); + try { + AddCoins(coins_view_cache, transaction, height, possible_overwrite); expected_code_path = true; + } catch (const std::logic_error& e) { + if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) { + assert(!possible_overwrite); + expected_code_path = true; + } } - } - assert(expected_code_path); - break; - } - case 1: { - (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache); - break; - } - case 2: { - TxValidationState state; - CAmount tx_fee_out; - const CTransaction transaction{random_mutable_transaction}; - if (ContainsSpentInput(transaction, coins_view_cache)) { - // Avoid: - // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed. - break; - } - try { - (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out); - assert(MoneyRange(tx_fee_out)); - } catch (const std::runtime_error&) { - } - break; - } - case 3: { - const CTransaction transaction{random_mutable_transaction}; - if (ContainsSpentInput(transaction, coins_view_cache)) { - // Avoid: - // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. - break; - } - (void)GetP2SHSigOpCount(transaction, coins_view_cache); - break; - } - case 4: { - const CTransaction transaction{random_mutable_transaction}; - if (ContainsSpentInput(transaction, coins_view_cache)) { - // Avoid: - // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. - break; - } - const int flags = fuzzed_data_provider.ConsumeIntegral<int>(); - if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) { - // Avoid: - // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed. - break; - } - (void)GetTransactionSigOpCost(transaction, coins_view_cache, flags); - break; - } - case 5: { - CCoinsStats stats; - bool expected_code_path = false; - try { - (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED); - } catch (const std::logic_error&) { - expected_code_path = true; - } - assert(expected_code_path); - break; - } - case 6: { - (void)IsWitnessStandard(CTransaction{random_mutable_transaction}, coins_view_cache); - break; - } - } + assert(expected_code_path); + }, + [&] { + (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false); + (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true); + }, + [&] { + TxValidationState state; + CAmount tx_fee_out; + const CTransaction transaction{random_mutable_transaction}; + if (ContainsSpentInput(transaction, coins_view_cache)) { + // Avoid: + // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed. + return; + } + try { + (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out); + assert(MoneyRange(tx_fee_out)); + } catch (const std::runtime_error&) { + } + }, + [&] { + const CTransaction transaction{random_mutable_transaction}; + if (ContainsSpentInput(transaction, coins_view_cache)) { + // Avoid: + // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. + return; + } + (void)GetP2SHSigOpCount(transaction, coins_view_cache); + }, + [&] { + const CTransaction transaction{random_mutable_transaction}; + if (ContainsSpentInput(transaction, coins_view_cache)) { + // Avoid: + // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed. + return; + } + const int flags = fuzzed_data_provider.ConsumeIntegral<int>(); + if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) { + // Avoid: + // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed. + return; + } + (void)GetTransactionSigOpCost(transaction, coins_view_cache, flags); + }, + [&] { + CCoinsStats stats; + bool expected_code_path = false; + try { + (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED); + } catch (const std::logic_error&) { + expected_code_path = true; + } + assert(expected_code_path); + }, + [&] { + (void)IsWitnessStandard(CTransaction{random_mutable_transaction}, coins_view_cache); + }); } } diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp new file mode 100644 index 0000000000..71b4b00116 --- /dev/null +++ b/src/test/fuzz/connman.cpp @@ -0,0 +1,149 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <chainparams.h> +#include <chainparamsbase.h> +#include <net.h> +#include <netaddress.h> +#include <protocol.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <util/translation.h> + +#include <cstdint> +#include <vector> + +void initialize_connman() +{ + static const auto testing_setup = MakeFuzzingContext<>(); +} + +FUZZ_TARGET_INIT(connman, initialize_connman) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + SetMockTime(ConsumeTime(fuzzed_data_provider)); + CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeBool()}; + CAddress random_address; + CNetAddr random_netaddr; + CNode random_node = ConsumeNode(fuzzed_data_provider); + CService random_service; + CSubNet random_subnet; + std::string random_string; + while (fuzzed_data_provider.ConsumeBool()) { + CallOneOf( + fuzzed_data_provider, + [&] { + random_address = ConsumeAddress(fuzzed_data_provider); + }, + [&] { + random_netaddr = ConsumeNetAddr(fuzzed_data_provider); + }, + [&] { + random_service = ConsumeService(fuzzed_data_provider); + }, + [&] { + random_subnet = ConsumeSubNet(fuzzed_data_provider); + }, + [&] { + random_string = fuzzed_data_provider.ConsumeRandomLengthString(64); + }, + [&] { + std::vector<CAddress> addresses; + while (fuzzed_data_provider.ConsumeBool()) { + addresses.push_back(ConsumeAddress(fuzzed_data_provider)); + } + // Limit nTimePenalty to int32_t to avoid signed integer overflow + (void)connman.AddNewAddresses(addresses, ConsumeAddress(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>()); + }, + [&] { + connman.AddNode(random_string); + }, + [&] { + connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + }, + [&] { + connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>()); + }, + [&] { + connman.DisconnectNode(random_netaddr); + }, + [&] { + connman.DisconnectNode(random_string); + }, + [&] { + connman.DisconnectNode(random_subnet); + }, + [&] { + connman.ForEachNode([](auto) {}); + }, + [&] { + connman.ForEachNodeThen([](auto) {}, []() {}); + }, + [&] { + (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); }); + }, + [&] { + (void)connman.GetAddresses(fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>()); + }, + [&] { + (void)connman.GetAddresses(random_node, fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>()); + }, + [&] { + (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + }, + [&] { + (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL})); + }, + [&] { + connman.MarkAddressGood(random_address); + }, + [&] { + (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool()); + }, + [&] { + // Limit now to int32_t to avoid signed integer overflow + (void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral<int32_t>(), fuzzed_data_provider.ConsumeIntegral<int>()); + }, + [&] { + CSerializedNetMsg serialized_net_msg; + serialized_net_msg.m_type = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE); + serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider); + connman.PushMessage(&random_node, std::move(serialized_net_msg)); + }, + [&] { + connman.RemoveAddedNode(random_string); + }, + [&] { + const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); + if (SanityCheckASMap(asmap)) { + connman.SetAsmap(asmap); + } + }, + [&] { + connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool()); + }, + [&] { + connman.SetServices(random_service, ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS)); + }, + [&] { + connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool()); + }); + } + (void)connman.GetAddedNodeInfo(); + (void)connman.GetExtraFullOutboundCount(); + (void)connman.GetLocalServices(); + (void)connman.GetMaxOutboundTarget(); + (void)connman.GetMaxOutboundTimeframe(); + (void)connman.GetMaxOutboundTimeLeftInCycle(); + (void)connman.GetNetworkActive(); + std::vector<CNodeStats> stats; + connman.GetNodeStats(stats); + (void)connman.GetOutboundTargetBytesLeft(); + (void)connman.GetReceiveFloodSize(); + (void)connman.GetTotalBytesRecv(); + (void)connman.GetTotalBytesSent(); + (void)connman.GetTryNewOutboundPeer(); + (void)connman.GetUseAddrmanOutgoing(); +} diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp index 664e65accc..c2bb3a1a4e 100644 --- a/src/test/fuzz/crypto.cpp +++ b/src/test/fuzz/crypto.cpp @@ -4,6 +4,7 @@ #include <crypto/hmac_sha256.h> #include <crypto/hmac_sha512.h> +#include <crypto/muhash.h> #include <crypto/ripemd160.h> #include <crypto/sha1.h> #include <crypto/sha256.h> @@ -17,7 +18,7 @@ #include <cstdint> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider); @@ -35,99 +36,98 @@ void test_one_input(const std::vector<uint8_t>& buffer) CSHA512 sha512; SHA3_256 sha3; CSipHasher sip_hasher{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()}; + MuHash3072 muhash; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 2)) { - case 0: { - if (fuzzed_data_provider.ConsumeBool()) { - data = ConsumeRandomLengthByteVector(fuzzed_data_provider); - if (data.empty()) { - data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); + CallOneOf( + fuzzed_data_provider, + [&] { + if (fuzzed_data_provider.ConsumeBool()) { + data = ConsumeRandomLengthByteVector(fuzzed_data_provider); + if (data.empty()) { + data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); + } } - } - (void)hash160.Write(data); - (void)hash256.Write(data); - (void)hmac_sha256.Write(data.data(), data.size()); - (void)hmac_sha512.Write(data.data(), data.size()); - (void)ripemd160.Write(data.data(), data.size()); - (void)sha1.Write(data.data(), data.size()); - (void)sha256.Write(data.data(), data.size()); - (void)sha3.Write(data); - (void)sha512.Write(data.data(), data.size()); - (void)sip_hasher.Write(data.data(), data.size()); + (void)hash160.Write(data); + (void)hash256.Write(data); + (void)hmac_sha256.Write(data.data(), data.size()); + (void)hmac_sha512.Write(data.data(), data.size()); + (void)ripemd160.Write(data.data(), data.size()); + (void)sha1.Write(data.data(), data.size()); + (void)sha256.Write(data.data(), data.size()); + (void)sha3.Write(data); + (void)sha512.Write(data.data(), data.size()); + (void)sip_hasher.Write(data.data(), data.size()); - (void)Hash(data); - (void)Hash160(data); - (void)sha512.Size(); - break; - } - case 1: { - (void)hash160.Reset(); - (void)hash256.Reset(); - (void)ripemd160.Reset(); - (void)sha1.Reset(); - (void)sha256.Reset(); - (void)sha3.Reset(); - (void)sha512.Reset(); - break; - } - case 2: { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 9)) { - case 0: { - data.resize(CHash160::OUTPUT_SIZE); - hash160.Finalize(data); - break; - } - case 1: { - data.resize(CHash256::OUTPUT_SIZE); - hash256.Finalize(data); - break; - } - case 2: { - data.resize(CHMAC_SHA256::OUTPUT_SIZE); - hmac_sha256.Finalize(data.data()); - break; - } - case 3: { - data.resize(CHMAC_SHA512::OUTPUT_SIZE); - hmac_sha512.Finalize(data.data()); - break; - } - case 4: { - data.resize(CRIPEMD160::OUTPUT_SIZE); - ripemd160.Finalize(data.data()); - break; - } - case 5: { - data.resize(CSHA1::OUTPUT_SIZE); - sha1.Finalize(data.data()); - break; - } - case 6: { - data.resize(CSHA256::OUTPUT_SIZE); - sha256.Finalize(data.data()); - break; - } - case 7: { - data.resize(CSHA512::OUTPUT_SIZE); - sha512.Finalize(data.data()); - break; - } - case 8: { - data.resize(1); - data[0] = sip_hasher.Finalize() % 256; - break; - } - case 9: { - data.resize(SHA3_256::OUTPUT_SIZE); - sha3.Finalize(data); - break; - } - } - break; - } - } + (void)Hash(data); + (void)Hash160(data); + (void)sha512.Size(); + + if (fuzzed_data_provider.ConsumeBool()) { + muhash *= MuHash3072(data); + } else { + muhash /= MuHash3072(data); + } + }, + [&] { + (void)hash160.Reset(); + (void)hash256.Reset(); + (void)ripemd160.Reset(); + (void)sha1.Reset(); + (void)sha256.Reset(); + (void)sha3.Reset(); + (void)sha512.Reset(); + muhash = MuHash3072(); + }, + [&] { + CallOneOf( + fuzzed_data_provider, + [&] { + data.resize(CHash160::OUTPUT_SIZE); + hash160.Finalize(data); + }, + [&] { + data.resize(CHash256::OUTPUT_SIZE); + hash256.Finalize(data); + }, + [&] { + data.resize(CHMAC_SHA256::OUTPUT_SIZE); + hmac_sha256.Finalize(data.data()); + }, + [&] { + data.resize(CHMAC_SHA512::OUTPUT_SIZE); + hmac_sha512.Finalize(data.data()); + }, + [&] { + data.resize(CRIPEMD160::OUTPUT_SIZE); + ripemd160.Finalize(data.data()); + }, + [&] { + data.resize(CSHA1::OUTPUT_SIZE); + sha1.Finalize(data.data()); + }, + [&] { + data.resize(CSHA256::OUTPUT_SIZE); + sha256.Finalize(data.data()); + }, + [&] { + data.resize(CSHA512::OUTPUT_SIZE); + sha512.Finalize(data.data()); + }, + [&] { + data.resize(1); + data[0] = sip_hasher.Finalize() % 256; + }, + [&] { + data.resize(SHA3_256::OUTPUT_SIZE); + sha3.Finalize(data); + }, + [&] { + uint256 out; + muhash.Finalize(out); + }); + }); } if (fuzzed_data_provider.ConsumeBool()) { uint64_t state[25]; diff --git a/src/test/fuzz/crypto_aes256.cpp b/src/test/fuzz/crypto_aes256.cpp index ae14073c96..ccabd1f7dc 100644 --- a/src/test/fuzz/crypto_aes256.cpp +++ b/src/test/fuzz/crypto_aes256.cpp @@ -11,7 +11,7 @@ #include <cstdint> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto_aes256) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; const std::vector<uint8_t> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, AES256_KEYSIZE); diff --git a/src/test/fuzz/crypto_aes256cbc.cpp b/src/test/fuzz/crypto_aes256cbc.cpp index 52983c7e79..6d4138e546 100644 --- a/src/test/fuzz/crypto_aes256cbc.cpp +++ b/src/test/fuzz/crypto_aes256cbc.cpp @@ -11,7 +11,7 @@ #include <cstdint> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto_aes256cbc) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; const std::vector<uint8_t> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, AES256_KEYSIZE); diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp index b7438d312d..bb8dd4594f 100644 --- a/src/test/fuzz/crypto_chacha20.cpp +++ b/src/test/fuzz/crypto_chacha20.cpp @@ -10,7 +10,7 @@ #include <cstdint> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto_chacha20) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; @@ -20,31 +20,26 @@ void test_one_input(const std::vector<uint8_t>& buffer) chacha20 = ChaCha20{key.data(), key.size()}; } while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 4)) { - case 0: { - const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); - chacha20.SetKey(key.data(), key.size()); - break; - } - case 1: { - chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); - break; - } - case 2: { - chacha20.Seek(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); - break; - } - case 3: { - std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); - chacha20.Keystream(output.data(), output.size()); - break; - } - case 4: { - std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); - const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size()); - chacha20.Crypt(input.data(), output.data(), input.size()); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); + chacha20.SetKey(key.data(), key.size()); + }, + [&] { + chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + }, + [&] { + chacha20.Seek(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + }, + [&] { + std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + chacha20.Keystream(output.data(), output.size()); + }, + [&] { + std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size()); + chacha20.Crypt(input.data(), output.data(), input.size()); + }); } } diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp index 48e4263f27..0e1c44cded 100644 --- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp +++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp @@ -13,7 +13,7 @@ #include <limits> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto_chacha20_poly1305_aead) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; @@ -29,44 +29,43 @@ void test_one_input(const std::vector<uint8_t>& buffer) std::vector<uint8_t> out(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); bool is_encrypt = fuzzed_data_provider.ConsumeBool(); while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 6)) { - case 0: { - buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(64, 4096); - in = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); - out = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); - break; - } - case 1: { - (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt); - break; - } - case 2: { - uint32_t len = 0; - const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data()); - assert(ok); - break; - } - case 3: { - seqnr_payload += 1; - aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN; - if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) { - aad_pos = 0; - seqnr_aad += 1; - } - break; - } - case 4: { - seqnr_payload = fuzzed_data_provider.ConsumeIntegral<int>(); - break; - } - case 5: { - seqnr_aad = fuzzed_data_provider.ConsumeIntegral<int>(); - break; - } - case 6: { - is_encrypt = fuzzed_data_provider.ConsumeBool(); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(64, 4096); + in = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); + out = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0); + }, + [&] { + (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt); + }, + [&] { + uint32_t len = 0; + const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data()); + assert(ok); + }, + [&] { + if (AdditionOverflow(seqnr_payload, static_cast<uint64_t>(1))) { + return; + } + seqnr_payload += 1; + aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN; + if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) { + aad_pos = 0; + if (AdditionOverflow(seqnr_aad, static_cast<uint64_t>(1))) { + return; + } + seqnr_aad += 1; + } + }, + [&] { + seqnr_payload = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); + }, + [&] { + seqnr_aad = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); + }, + [&] { + is_encrypt = fuzzed_data_provider.ConsumeBool(); + }); } } diff --git a/src/test/fuzz/crypto_common.cpp b/src/test/fuzz/crypto_common.cpp index 7ccb125216..8e07dfedb9 100644 --- a/src/test/fuzz/crypto_common.cpp +++ b/src/test/fuzz/crypto_common.cpp @@ -13,7 +13,7 @@ #include <cstring> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto_common) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; const uint16_t random_u16 = fuzzed_data_provider.ConsumeIntegral<uint16_t>(); diff --git a/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp b/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp index e0a4e90c10..8cb9c55283 100644 --- a/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp +++ b/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp @@ -11,7 +11,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto_hkdf_hmac_sha256_l32) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; diff --git a/src/test/fuzz/crypto_poly1305.cpp b/src/test/fuzz/crypto_poly1305.cpp index 5681e6a693..ac555ed68c 100644 --- a/src/test/fuzz/crypto_poly1305.cpp +++ b/src/test/fuzz/crypto_poly1305.cpp @@ -10,7 +10,7 @@ #include <cstdint> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(crypto_poly1305) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; diff --git a/src/test/fuzz/cuckoocache.cpp b/src/test/fuzz/cuckoocache.cpp index 5b45aa79d8..dc20dc3f62 100644 --- a/src/test/fuzz/cuckoocache.cpp +++ b/src/test/fuzz/cuckoocache.cpp @@ -26,7 +26,7 @@ struct RandomHasher { }; } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(cuckoocache) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); fuzzed_data_provider_ptr = &fuzzed_data_provider; diff --git a/src/test/fuzz/danger_link_all.sh b/src/test/fuzz/danger_link_all.sh new file mode 100755 index 0000000000..2ddd00c658 --- /dev/null +++ b/src/test/fuzz/danger_link_all.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Copyright (c) 2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +export LC_ALL=C.UTF-8 + +set -e + +ROOT_DIR="$(git rev-parse --show-toplevel)" + +# Run only once (break make recursion) +if [ -d "${ROOT_DIR}/lock_fuzz_link_all" ]; then + exit +fi +mkdir "${ROOT_DIR}/lock_fuzz_link_all" + +echo "Linking each fuzz target separately." +for FUZZING_HARNESS in $(PRINT_ALL_FUZZ_TARGETS_AND_ABORT=1 "${ROOT_DIR}/src/test/fuzz/fuzz" | sort -u); do + echo "Building src/test/fuzz/${FUZZING_HARNESS} ..." + git checkout -- "${ROOT_DIR}/src/test/fuzz/fuzz.cpp" + sed -i "s/std::getenv(\"FUZZ\")/\"${FUZZING_HARNESS}\"/g" "${ROOT_DIR}/src/test/fuzz/fuzz.cpp" + make + mv "${ROOT_DIR}/src/test/fuzz/fuzz" "${ROOT_DIR}/src/test/fuzz/${FUZZING_HARNESS}" +done +git checkout -- "${ROOT_DIR}/src/test/fuzz/fuzz.cpp" +rmdir "${ROOT_DIR}/lock_fuzz_link_all" +echo "Successfully built all fuzz targets." diff --git a/src/test/fuzz/data_stream.cpp b/src/test/fuzz/data_stream.cpp new file mode 100644 index 0000000000..f3b6e6af04 --- /dev/null +++ b/src/test/fuzz/data_stream.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <addrman.h> +#include <net.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <cstdint> +#include <vector> + +void initialize_data_stream_addr_man() +{ + static const auto testing_setup = MakeFuzzingContext<>(); +} + +FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); + CAddrMan addr_man; + CAddrDB::Read(addr_man, data_stream); +} diff --git a/src/test/fuzz/decode_tx.cpp b/src/test/fuzz/decode_tx.cpp index 0d89d4228a..57431e65ba 100644 --- a/src/test/fuzz/decode_tx.cpp +++ b/src/test/fuzz/decode_tx.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,20 +12,21 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(decode_tx) { const std::string tx_hex = HexStr(buffer); CMutableTransaction mtx; const bool result_none = DecodeHexTx(mtx, tx_hex, false, false); const bool result_try_witness = DecodeHexTx(mtx, tx_hex, false, true); const bool result_try_witness_and_maybe_no_witness = DecodeHexTx(mtx, tx_hex, true, true); - const bool result_try_no_witness = DecodeHexTx(mtx, tx_hex, true, false); + CMutableTransaction no_witness_mtx; + const bool result_try_no_witness = DecodeHexTx(no_witness_mtx, tx_hex, true, false); assert(!result_none); if (result_try_witness_and_maybe_no_witness) { assert(result_try_no_witness || result_try_witness); } - // if (result_try_no_witness) { // Uncomment when https://github.com/bitcoin/bitcoin/pull/17775 is merged - if (result_try_witness) { // Remove stop-gap when https://github.com/bitcoin/bitcoin/pull/17775 is merged + if (result_try_no_witness) { + assert(!no_witness_mtx.HasWitness()); assert(result_try_witness_and_maybe_no_witness); } } diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index 001758ffdb..0d1921f285 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -8,13 +8,14 @@ #include <test/fuzz/fuzz.h> #include <util/memory.h> -void initialize() +void initialize_descriptor_parse() { static const ECCVerifyHandle verify_handle; - SelectParams(CBaseChainParams::REGTEST); + ECC_Start(); + SelectParams(CBaseChainParams::MAIN); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(descriptor_parse, initialize_descriptor_parse) { const std::string descriptor(buffer.begin(), buffer.end()); FlatSigningProvider signing_provider; diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index b799d3b43b..74dec6475e 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -13,7 +13,9 @@ #include <key.h> #include <merkleblock.h> #include <net.h> +#include <netbase.h> #include <node/utxo_snapshot.h> +#include <optional.h> #include <primitives/block.h> #include <protocol.h> #include <psbt.h> @@ -32,21 +34,30 @@ #include <test/fuzz/fuzz.h> -void initialize() +void initialize_deserialize() { // Fuzzers using pubkey must hold an ECCVerifyHandle. static const ECCVerifyHandle verify_handle; } +#define FUZZ_TARGET_DESERIALIZE(name, code) \ + FUZZ_TARGET_INIT(name, initialize_deserialize) \ + { \ + try { \ + code \ + } catch (const invalid_fuzzing_input_exception&) { \ + } \ + } + namespace { struct invalid_fuzzing_input_exception : public std::exception { }; template <typename T> -CDataStream Serialize(const T& obj) +CDataStream Serialize(const T& obj, const int version = INIT_PROTO_VERSION) { - CDataStream ds(SER_NETWORK, INIT_PROTO_VERSION); + CDataStream ds(SER_NETWORK, version); ds << obj; return ds; } @@ -60,15 +71,19 @@ T Deserialize(CDataStream ds) } template <typename T> -void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj) +void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj, const Optional<int> protocol_version = nullopt) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); - try { - int version; - ds >> version; - ds.SetVersion(version); - } catch (const std::ios_base::failure&) { - throw invalid_fuzzing_input_exception(); + if (protocol_version) { + ds.SetVersion(*protocol_version); + } else { + try { + int version; + ds >> version; + ds.SetVersion(version); + } catch (const std::ios_base::failure&) { + throw invalid_fuzzing_input_exception(); + } } try { ds >> obj; @@ -79,159 +94,209 @@ void DeserializeFromFuzzingInput(const std::vector<uint8_t>& buffer, T& obj) } template <typename T> -void AssertEqualAfterSerializeDeserialize(const T& obj) +void AssertEqualAfterSerializeDeserialize(const T& obj, const int version = INIT_PROTO_VERSION) { - assert(Deserialize<T>(Serialize(obj)) == obj); + assert(Deserialize<T>(Serialize(obj, version)) == obj); } } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) -{ - try { -#if BLOCK_FILTER_DESERIALIZE +FUZZ_TARGET_DESERIALIZE(block_filter_deserialize, { BlockFilter block_filter; DeserializeFromFuzzingInput(buffer, block_filter); -#elif ADDR_INFO_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(addr_info_deserialize, { CAddrInfo addr_info; DeserializeFromFuzzingInput(buffer, addr_info); -#elif BLOCK_FILE_INFO_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(block_file_info_deserialize, { CBlockFileInfo block_file_info; DeserializeFromFuzzingInput(buffer, block_file_info); -#elif BLOCK_HEADER_AND_SHORT_TXIDS_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(block_header_and_short_txids_deserialize, { CBlockHeaderAndShortTxIDs block_header_and_short_txids; DeserializeFromFuzzingInput(buffer, block_header_and_short_txids); -#elif FEE_RATE_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(fee_rate_deserialize, { CFeeRate fee_rate; DeserializeFromFuzzingInput(buffer, fee_rate); AssertEqualAfterSerializeDeserialize(fee_rate); -#elif MERKLE_BLOCK_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(merkle_block_deserialize, { CMerkleBlock merkle_block; DeserializeFromFuzzingInput(buffer, merkle_block); -#elif OUT_POINT_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(out_point_deserialize, { COutPoint out_point; DeserializeFromFuzzingInput(buffer, out_point); AssertEqualAfterSerializeDeserialize(out_point); -#elif PARTIAL_MERKLE_TREE_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(partial_merkle_tree_deserialize, { CPartialMerkleTree partial_merkle_tree; DeserializeFromFuzzingInput(buffer, partial_merkle_tree); -#elif PUB_KEY_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(pub_key_deserialize, { CPubKey pub_key; DeserializeFromFuzzingInput(buffer, pub_key); // TODO: The following equivalence should hold for CPubKey? Fix. // AssertEqualAfterSerializeDeserialize(pub_key); -#elif SCRIPT_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(script_deserialize, { CScript script; DeserializeFromFuzzingInput(buffer, script); -#elif SUB_NET_DESERIALIZE - CSubNet sub_net; - DeserializeFromFuzzingInput(buffer, sub_net); - AssertEqualAfterSerializeDeserialize(sub_net); -#elif TX_IN_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(sub_net_deserialize, { + CSubNet sub_net_1; + DeserializeFromFuzzingInput(buffer, sub_net_1, INIT_PROTO_VERSION); + AssertEqualAfterSerializeDeserialize(sub_net_1, INIT_PROTO_VERSION); + CSubNet sub_net_2; + DeserializeFromFuzzingInput(buffer, sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT); + AssertEqualAfterSerializeDeserialize(sub_net_2, INIT_PROTO_VERSION | ADDRV2_FORMAT); + CSubNet sub_net_3; + DeserializeFromFuzzingInput(buffer, sub_net_3); + AssertEqualAfterSerializeDeserialize(sub_net_3, INIT_PROTO_VERSION | ADDRV2_FORMAT); +}) +FUZZ_TARGET_DESERIALIZE(tx_in_deserialize, { CTxIn tx_in; DeserializeFromFuzzingInput(buffer, tx_in); AssertEqualAfterSerializeDeserialize(tx_in); -#elif FLAT_FILE_POS_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(flat_file_pos_deserialize, { FlatFilePos flat_file_pos; DeserializeFromFuzzingInput(buffer, flat_file_pos); AssertEqualAfterSerializeDeserialize(flat_file_pos); -#elif KEY_ORIGIN_INFO_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(key_origin_info_deserialize, { KeyOriginInfo key_origin_info; DeserializeFromFuzzingInput(buffer, key_origin_info); AssertEqualAfterSerializeDeserialize(key_origin_info); -#elif PARTIALLY_SIGNED_TRANSACTION_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(partially_signed_transaction_deserialize, { PartiallySignedTransaction partially_signed_transaction; DeserializeFromFuzzingInput(buffer, partially_signed_transaction); -#elif PREFILLED_TRANSACTION_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(prefilled_transaction_deserialize, { PrefilledTransaction prefilled_transaction; DeserializeFromFuzzingInput(buffer, prefilled_transaction); -#elif PSBT_INPUT_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(psbt_input_deserialize, { PSBTInput psbt_input; DeserializeFromFuzzingInput(buffer, psbt_input); -#elif PSBT_OUTPUT_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(psbt_output_deserialize, { PSBTOutput psbt_output; DeserializeFromFuzzingInput(buffer, psbt_output); -#elif BLOCK_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(block_deserialize, { CBlock block; DeserializeFromFuzzingInput(buffer, block); -#elif BLOCKLOCATOR_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(blocklocator_deserialize, { CBlockLocator bl; DeserializeFromFuzzingInput(buffer, bl); -#elif BLOCKMERKLEROOT +}) +FUZZ_TARGET_DESERIALIZE(blockmerkleroot, { CBlock block; DeserializeFromFuzzingInput(buffer, block); bool mutated; BlockMerkleRoot(block, &mutated); -#elif ADDRMAN_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(addrman_deserialize, { CAddrMan am; DeserializeFromFuzzingInput(buffer, am); -#elif BLOCKHEADER_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { CBlockHeader bh; DeserializeFromFuzzingInput(buffer, bh); -#elif BANENTRY_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(banentry_deserialize, { CBanEntry be; DeserializeFromFuzzingInput(buffer, be); -#elif TXUNDO_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(txundo_deserialize, { CTxUndo tu; DeserializeFromFuzzingInput(buffer, tu); -#elif BLOCKUNDO_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(blockundo_deserialize, { CBlockUndo bu; DeserializeFromFuzzingInput(buffer, bu); -#elif COINS_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(coins_deserialize, { Coin coin; DeserializeFromFuzzingInput(buffer, coin); -#elif NETADDR_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(netaddr_deserialize, { CNetAddr na; DeserializeFromFuzzingInput(buffer, na); - AssertEqualAfterSerializeDeserialize(na); -#elif SERVICE_DESERIALIZE + if (na.IsAddrV1Compatible()) { + AssertEqualAfterSerializeDeserialize(na); + } + AssertEqualAfterSerializeDeserialize(na, INIT_PROTO_VERSION | ADDRV2_FORMAT); +}) +FUZZ_TARGET_DESERIALIZE(service_deserialize, { CService s; DeserializeFromFuzzingInput(buffer, s); - AssertEqualAfterSerializeDeserialize(s); -#elif MESSAGEHEADER_DESERIALIZE + if (s.IsAddrV1Compatible()) { + AssertEqualAfterSerializeDeserialize(s); + } + AssertEqualAfterSerializeDeserialize(s, INIT_PROTO_VERSION | ADDRV2_FORMAT); + CService s1; + DeserializeFromFuzzingInput(buffer, s1, INIT_PROTO_VERSION); + AssertEqualAfterSerializeDeserialize(s1, INIT_PROTO_VERSION); + assert(s1.IsAddrV1Compatible()); + CService s2; + DeserializeFromFuzzingInput(buffer, s2, INIT_PROTO_VERSION | ADDRV2_FORMAT); + AssertEqualAfterSerializeDeserialize(s2, INIT_PROTO_VERSION | ADDRV2_FORMAT); +}) +FUZZ_TARGET_DESERIALIZE(messageheader_deserialize, { CMessageHeader mh; DeserializeFromFuzzingInput(buffer, mh); (void)mh.IsCommandValid(); -#elif ADDRESS_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(address_deserialize, { CAddress a; DeserializeFromFuzzingInput(buffer, a); -#elif INV_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(inv_deserialize, { CInv i; DeserializeFromFuzzingInput(buffer, i); -#elif BLOOMFILTER_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(bloomfilter_deserialize, { CBloomFilter bf; DeserializeFromFuzzingInput(buffer, bf); -#elif DISKBLOCKINDEX_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(diskblockindex_deserialize, { CDiskBlockIndex dbi; DeserializeFromFuzzingInput(buffer, dbi); -#elif TXOUTCOMPRESSOR_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(txoutcompressor_deserialize, { CTxOut to; auto toc = Using<TxOutCompression>(to); DeserializeFromFuzzingInput(buffer, toc); -#elif BLOCKTRANSACTIONS_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(blocktransactions_deserialize, { BlockTransactions bt; DeserializeFromFuzzingInput(buffer, bt); -#elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(blocktransactionsrequest_deserialize, { BlockTransactionsRequest btr; DeserializeFromFuzzingInput(buffer, btr); -#elif SNAPSHOTMETADATA_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(snapshotmetadata_deserialize, { SnapshotMetadata snapshot_metadata; DeserializeFromFuzzingInput(buffer, snapshot_metadata); -#elif UINT160_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(uint160_deserialize, { uint160 u160; DeserializeFromFuzzingInput(buffer, u160); AssertEqualAfterSerializeDeserialize(u160); -#elif UINT256_DESERIALIZE +}) +FUZZ_TARGET_DESERIALIZE(uint256_deserialize, { uint256 u256; DeserializeFromFuzzingInput(buffer, u256); AssertEqualAfterSerializeDeserialize(u256); -#else -#error Need at least one fuzz target to compile -#endif +}) // Classes intentionally not covered in this file since their deserialization code is // fuzzed elsewhere: // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp - } catch (const invalid_fuzzing_input_exception&) { - } -} diff --git a/src/test/fuzz/eval_script.cpp b/src/test/fuzz/eval_script.cpp index c556599db3..635288fc36 100644 --- a/src/test/fuzz/eval_script.cpp +++ b/src/test/fuzz/eval_script.cpp @@ -10,12 +10,12 @@ #include <limits> -void initialize() +void initialize_eval_script() { static const ECCVerifyHandle verify_handle; } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(eval_script, initialize_eval_script) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); diff --git a/src/test/fuzz/fee_rate.cpp b/src/test/fuzz/fee_rate.cpp index f3d44d9f93..2955213635 100644 --- a/src/test/fuzz/fee_rate.cpp +++ b/src/test/fuzz/fee_rate.cpp @@ -13,7 +13,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(fee_rate) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const CAmount satoshis_per_k = ConsumeMoney(fuzzed_data_provider); diff --git a/src/test/fuzz/fees.cpp b/src/test/fuzz/fees.cpp index ce8700befa..61c7681bf9 100644 --- a/src/test/fuzz/fees.cpp +++ b/src/test/fuzz/fees.cpp @@ -13,7 +13,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(fees) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const CFeeRate minimal_incremental_fee{ConsumeMoney(fuzzed_data_provider)}; diff --git a/src/test/fuzz/flatfile.cpp b/src/test/fuzz/flatfile.cpp index 95dabb8bab..d142e374b1 100644 --- a/src/test/fuzz/flatfile.cpp +++ b/src/test/fuzz/flatfile.cpp @@ -13,7 +13,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(flatfile) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); std::optional<FlatFilePos> flat_file_pos = ConsumeDeserializable<FlatFilePos>(fuzzed_data_provider); diff --git a/src/test/fuzz/float.cpp b/src/test/fuzz/float.cpp index a24bae5b35..d18a87d177 100644 --- a/src/test/fuzz/float.cpp +++ b/src/test/fuzz/float.cpp @@ -12,7 +12,7 @@ #include <cassert> #include <cstdint> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(float) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 1e1807d734..fd87667755 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -5,6 +5,7 @@ #include <test/fuzz/fuzz.h> #include <test/util/setup_common.h> +#include <util/check.h> #include <cstdint> #include <unistd.h> @@ -12,14 +13,35 @@ const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; -// Decide if main(...) should be provided: -// * AFL needs main(...) regardless of platform. -// * macOS handles __attribute__((weak)) main(...) poorly when linking -// against libFuzzer. See https://github.com/bitcoin/bitcoin/pull/18008 -// for details. -#if defined(__AFL_COMPILER) || !defined(MAC_OSX) -#define PROVIDE_MAIN_FUNCTION -#endif +std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize>>& FuzzTargets() +{ + static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize>> g_fuzz_targets; + return g_fuzz_targets; +} + +void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init) +{ + const auto it_ins = FuzzTargets().try_emplace(name, std::move(target), std::move(init)); + Assert(it_ins.second); +} + +static TypeTestOneInput* g_test_one_input{nullptr}; + +void initialize() +{ + if (std::getenv("PRINT_ALL_FUZZ_TARGETS_AND_ABORT")) { + for (const auto& t : FuzzTargets()) { + std::cout << t.first << std::endl; + } + Assert(false); + } + std::string_view fuzz_target{Assert(std::getenv("FUZZ"))}; + const auto it = FuzzTargets().find(fuzz_target); + Assert(it != FuzzTargets().end()); + Assert(!g_test_one_input); + g_test_one_input = &std::get<0>(it->second); + std::get<1>(it->second)(); +} #if defined(PROVIDE_MAIN_FUNCTION) static bool read_stdin(std::vector<uint8_t>& data) @@ -33,14 +55,10 @@ static bool read_stdin(std::vector<uint8_t>& data) } #endif -// Default initialization: Override using a non-weak initialize(). -__attribute__((weak)) void initialize() -{ -} - // This function is used by libFuzzer extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + static const auto& test_one_input = *Assert(g_test_one_input); const std::vector<uint8_t> input(data, data + size); test_one_input(input); return 0; @@ -57,6 +75,7 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) __attribute__((weak)) int main(int argc, char** argv) { initialize(); + static const auto& test_one_input = *Assert(g_test_one_input); #ifdef __AFL_INIT // Enable AFL deferred forkserver mode. Requires compilation using // afl-clang-fast++. See fuzzing.md for details. diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h index 3be202b16e..52841e069a 100644 --- a/src/test/fuzz/fuzz.h +++ b/src/test/fuzz/fuzz.h @@ -1,14 +1,33 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_TEST_FUZZ_FUZZ_H #define BITCOIN_TEST_FUZZ_FUZZ_H -#include <stdint.h> +#include <cstdint> +#include <functional> +#include <string_view> #include <vector> -void initialize(); -void test_one_input(const std::vector<uint8_t>& buffer); +using TypeTestOneInput = std::function<void(const std::vector<uint8_t>&)>; +using TypeInitialize = std::function<void()>; + +void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init); + +inline void FuzzFrameworkEmptyFun() {} + +#define FUZZ_TARGET(name) \ + FUZZ_TARGET_INIT(name, FuzzFrameworkEmptyFun) + +#define FUZZ_TARGET_INIT(name, init_fun) \ + void name##_fuzz_target(const std::vector<uint8_t>&); \ + struct name##_Before_Main { \ + name##_Before_Main() \ + { \ + FuzzFrameworkRegisterTarget(#name, name##_fuzz_target, init_fun); \ + } \ + } const static g_##name##_before_main; \ + void name##_fuzz_target(const std::vector<uint8_t>& buffer) #endif // BITCOIN_TEST_FUZZ_FUZZ_H diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp index a9f450b0c4..c99bf940c7 100644 --- a/src/test/fuzz/golomb_rice.cpp +++ b/src/test/fuzz/golomb_rice.cpp @@ -54,7 +54,7 @@ std::vector<uint64_t> BuildHashedSet(const std::unordered_set<std::vector<uint8_ } } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(golomb_rice) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); std::vector<uint8_t> golomb_rice_data; diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp index 6a8699fd0f..cc1bc1c8cf 100644 --- a/src/test/fuzz/hex.cpp +++ b/src/test/fuzz/hex.cpp @@ -16,12 +16,12 @@ #include <string> #include <vector> -void initialize() +void initialize_hex() { static const ECCVerifyHandle verify_handle; } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(hex, initialize_hex) { const std::string random_hex_string(buffer.begin(), buffer.end()); const std::vector<unsigned char> data = ParseHex(random_hex_string); diff --git a/src/test/fuzz/http_request.cpp b/src/test/fuzz/http_request.cpp index 36d44e361f..e3b62032bc 100644 --- a/src/test/fuzz/http_request.cpp +++ b/src/test/fuzz/http_request.cpp @@ -39,7 +39,7 @@ extern "C" int evhttp_parse_headers_(struct evhttp_request*, struct evbuffer*); std::string RequestMethodString(HTTPRequest::RequestMethod m); -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(http_request) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; evhttp_request* evreq = evhttp_request_new(nullptr, nullptr); diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index 35d6804d4f..ac83d91ea0 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -40,12 +40,12 @@ #include <set> #include <vector> -void initialize() +void initialize_integer() { SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(integer, initialize_integer) { if (buffer.size() < sizeof(uint256) + sizeof(uint160)) { return; diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp index 955b954700..aa8f826e4a 100644 --- a/src/test/fuzz/key.cpp +++ b/src/test/fuzz/key.cpp @@ -26,14 +26,14 @@ #include <string> #include <vector> -void initialize() +void initialize_key() { static const ECCVerifyHandle ecc_verify_handle; ECC_Start(); SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(key, initialize_key) { const CKey key = [&] { CKey k; diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp index 62aefb650d..665ca01fa1 100644 --- a/src/test/fuzz/key_io.cpp +++ b/src/test/fuzz/key_io.cpp @@ -14,14 +14,14 @@ #include <string> #include <vector> -void initialize() +void initialize_key_io() { static const ECCVerifyHandle verify_handle; ECC_Start(); SelectParams(CBaseChainParams::MAIN); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(key_io, initialize_key_io) { const std::string random_string(buffer.begin(), buffer.end()); diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp index 82cbc00a3a..fa4024fc38 100644 --- a/src/test/fuzz/kitchen_sink.cpp +++ b/src/test/fuzz/kitchen_sink.cpp @@ -2,6 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <merkleblock.h> +#include <policy/fees.h> #include <rpc/util.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> @@ -9,18 +11,49 @@ #include <util/error.h> #include <util/translation.h> +#include <array> #include <cstdint> #include <vector> +namespace { +constexpr TransactionError ALL_TRANSACTION_ERROR[] = { + TransactionError::OK, + TransactionError::MISSING_INPUTS, + TransactionError::ALREADY_IN_CHAIN, + TransactionError::P2P_DISABLED, + TransactionError::MEMPOOL_REJECTED, + TransactionError::MEMPOOL_ERROR, + TransactionError::INVALID_PSBT, + TransactionError::PSBT_MISMATCH, + TransactionError::SIGHASH_MISMATCH, + TransactionError::MAX_FEE_EXCEEDED, +}; +}; // namespace + // The fuzzing kitchen sink: Fuzzing harness for functions that need to be // fuzzed but a.) don't belong in any existing fuzzing harness file, and // b.) are not important enough to warrant their own fuzzing harness file. -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(kitchen_sink) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray<TransactionError>({TransactionError::OK, TransactionError::MISSING_INPUTS, TransactionError::ALREADY_IN_CHAIN, TransactionError::P2P_DISABLED, TransactionError::MEMPOOL_REJECTED, TransactionError::MEMPOOL_ERROR, TransactionError::INVALID_PSBT, TransactionError::PSBT_MISMATCH, TransactionError::SIGHASH_MISMATCH, TransactionError::MAX_FEE_EXCEEDED}); + const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray(ALL_TRANSACTION_ERROR); (void)JSONRPCTransactionError(transaction_error); (void)RPCErrorFromTransactionError(transaction_error); (void)TransactionErrorString(transaction_error); + + (void)StringForFeeEstimateHorizon(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS)); + + const OutputType output_type = fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES); + const std::string& output_type_string = FormatOutputType(output_type); + OutputType output_type_parsed; + const bool parsed = ParseOutputType(output_type_string, output_type_parsed); + assert(parsed); + assert(output_type == output_type_parsed); + (void)ParseOutputType(fuzzed_data_provider.ConsumeRandomLengthString(64), output_type_parsed); + + const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); + const std::vector<bool> bits = BytesToBits(bytes); + const std::vector<uint8_t> bytes_decoded = BitsToBytes(bits); + assert(bytes == bytes_decoded); } diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp index d9de9d9866..207ee586bc 100644 --- a/src/test/fuzz/load_external_block_file.cpp +++ b/src/test/fuzz/load_external_block_file.cpp @@ -13,12 +13,12 @@ #include <cstdint> #include <vector> -void initialize() +void initialize_load_external_block_file() { - InitializeFuzzingContext(); + static const auto testing_setup = MakeFuzzingContext<const TestingSetup>(); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider); diff --git a/src/test/fuzz/locale.cpp b/src/test/fuzz/locale.cpp index 2b181c6da1..5b1acae57b 100644 --- a/src/test/fuzz/locale.cpp +++ b/src/test/fuzz/locale.cpp @@ -35,7 +35,7 @@ bool IsAvailableLocale(const std::string& locale_identifier) } } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(locale) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::string locale_identifier = ConsumeLocaleIdentifier(fuzzed_data_provider); diff --git a/src/test/fuzz/merkleblock.cpp b/src/test/fuzz/merkleblock.cpp index c44e334272..23e0baa564 100644 --- a/src/test/fuzz/merkleblock.cpp +++ b/src/test/fuzz/merkleblock.cpp @@ -13,15 +13,37 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(merkleblock) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - std::optional<CPartialMerkleTree> partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider); - if (!partial_merkle_tree) { - return; - } - (void)partial_merkle_tree->GetNumTransactions(); + CPartialMerkleTree partial_merkle_tree; + CallOneOf( + fuzzed_data_provider, + [&] { + const std::optional<CPartialMerkleTree> opt_partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider); + if (opt_partial_merkle_tree) { + partial_merkle_tree = *opt_partial_merkle_tree; + } + }, + [&] { + CMerkleBlock merkle_block; + const std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider); + CBloomFilter bloom_filter; + std::set<uint256> txids; + if (opt_block && !opt_block->vtx.empty()) { + if (fuzzed_data_provider.ConsumeBool()) { + merkle_block = CMerkleBlock{*opt_block, bloom_filter}; + } else if (fuzzed_data_provider.ConsumeBool()) { + while (fuzzed_data_provider.ConsumeBool()) { + txids.insert(ConsumeUInt256(fuzzed_data_provider)); + } + merkle_block = CMerkleBlock{*opt_block, txids}; + } + } + partial_merkle_tree = merkle_block.txn; + }); + (void)partial_merkle_tree.GetNumTransactions(); std::vector<uint256> matches; std::vector<unsigned int> indices; - (void)partial_merkle_tree->ExtractMatches(matches, indices); + (void)partial_merkle_tree.ExtractMatches(matches, indices); } diff --git a/src/test/fuzz/message.cpp b/src/test/fuzz/message.cpp index fa0322a391..06cd0afe2a 100644 --- a/src/test/fuzz/message.cpp +++ b/src/test/fuzz/message.cpp @@ -16,14 +16,14 @@ #include <string> #include <vector> -void initialize() +void initialize_message() { static const ECCVerifyHandle ecc_verify_handle; ECC_Start(); SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(message, initialize_message) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::string random_message = fuzzed_data_provider.ConsumeRandomLengthString(1024); diff --git a/src/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp new file mode 100644 index 0000000000..8f843ca773 --- /dev/null +++ b/src/test/fuzz/muhash.cpp @@ -0,0 +1,53 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <crypto/muhash.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <vector> + +FUZZ_TARGET(muhash) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider); + std::vector<uint8_t> data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider); + if (data.empty()) { + data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); + } + if (data2.empty()) { + data2.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); + } + + data = ConsumeRandomLengthByteVector(fuzzed_data_provider); + data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider); + + MuHash3072 muhash; + + // Test that MuHash result is consistent independent of order of operations + muhash.Insert(data); + muhash.Insert(data2); + + uint256 out; + muhash.Finalize(out); + + muhash = MuHash3072(); + muhash.Insert(data2); + muhash.Insert(data); + + uint256 out2; + muhash.Finalize(out2); + + assert(out == out2); + + // Test that removing all added elements brings the object back to it's initial state + muhash /= muhash; + muhash.Finalize(out); + + MuHash3072 muhash2; + muhash2.Finalize(out2); + + assert(out == out2); +} diff --git a/src/test/fuzz/multiplication_overflow.cpp b/src/test/fuzz/multiplication_overflow.cpp index a4b158c18b..0f054529a6 100644 --- a/src/test/fuzz/multiplication_overflow.cpp +++ b/src/test/fuzz/multiplication_overflow.cpp @@ -14,7 +14,7 @@ #if __has_builtin(__builtin_mul_overflow) #define HAVE_BUILTIN_MUL_OVERFLOW #endif -#elif defined(__GNUC__) && (__GNUC__ >= 5) +#elif defined(__GNUC__) #define HAVE_BUILTIN_MUL_OVERFLOW #endif @@ -40,7 +40,7 @@ void TestMultiplicationOverflow(FuzzedDataProvider& fuzzed_data_provider) } } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(multiplication_overflow) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); TestMultiplicationOverflow<int64_t>(fuzzed_data_provider); diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp index a85c353243..21dca4eb05 100644 --- a/src/test/fuzz/net.cpp +++ b/src/test/fuzz/net.cpp @@ -13,124 +13,93 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/util/net.h> #include <test/util/setup_common.h> #include <cstdint> #include <string> #include <vector> -void initialize() +void initialize_net() { - static const BasicTestingSetup basic_testing_setup; + static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::MAIN); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(net, initialize_net) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - - const std::optional<CAddress> address = ConsumeDeserializable<CAddress>(fuzzed_data_provider); - if (!address) { - return; - } - const std::optional<CAddress> address_bind = ConsumeDeserializable<CAddress>(fuzzed_data_provider); - if (!address_bind) { - return; - } - - CNode node{fuzzed_data_provider.ConsumeIntegral<NodeId>(), - static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()), - fuzzed_data_provider.ConsumeIntegral<int>(), - INVALID_SOCKET, - *address, - fuzzed_data_provider.ConsumeIntegral<uint64_t>(), - fuzzed_data_provider.ConsumeIntegral<uint64_t>(), - *address_bind, - fuzzed_data_provider.ConsumeRandomLengthString(32), - fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH})}; + SetMockTime(ConsumeTime(fuzzed_data_provider)); + CNode node{ConsumeNode(fuzzed_data_provider)}; + node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>()); while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) { - case 0: { - node.CloseSocketDisconnect(); - break; - } - case 1: { - node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32)); - break; - } - case 2: { - node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>()); - break; - } - case 3: { - const std::vector<bool> asmap = ConsumeRandomLengthIntegralVector<bool>(fuzzed_data_provider, 128); - if (!SanityCheckASMap(asmap)) { - break; - } - CNodeStats stats; - node.copyStats(stats, asmap); - break; - } - case 4: { - const CNode* add_ref_node = node.AddRef(); - assert(add_ref_node == &node); - break; - } - case 5: { - if (node.GetRefCount() > 0) { - node.Release(); - } - break; - } - case 6: { - if (node.m_addr_known == nullptr) { - break; - } - const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider); - if (!addr_opt) { - break; - } - node.AddAddressKnown(*addr_opt); - break; - } - case 7: { - if (node.m_addr_known == nullptr) { - break; - } - const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider); - if (!addr_opt) { - break; - } - FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; - node.PushAddress(*addr_opt, fast_random_context); - break; - } - case 8: { - const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider); - if (!inv_opt) { - break; - } - node.AddKnownTx(inv_opt->hash); - break; - } - case 9: { - node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider)); - break; - } - case 10: { - const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider); - if (!service_opt) { - break; - } - node.SetAddrLocal(*service_opt); - break; - } - case 11: { - const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); - bool complete; - node.ReceiveMsgBytes((const char*)b.data(), b.size(), complete); - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + node.CloseSocketDisconnect(); + }, + [&] { + node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32)); + }, + [&] { + const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); + if (!SanityCheckASMap(asmap)) { + return; + } + CNodeStats stats; + node.copyStats(stats, asmap); + }, + [&] { + const CNode* add_ref_node = node.AddRef(); + assert(add_ref_node == &node); + }, + [&] { + if (node.GetRefCount() > 0) { + node.Release(); + } + }, + [&] { + if (node.m_addr_known == nullptr) { + return; + } + const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + if (!addr_opt) { + return; + } + node.AddAddressKnown(*addr_opt); + }, + [&] { + if (node.m_addr_known == nullptr) { + return; + } + const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + if (!addr_opt) { + return; + } + FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; + node.PushAddress(*addr_opt, fast_random_context); + }, + [&] { + const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider); + if (!inv_opt) { + return; + } + node.AddKnownTx(inv_opt->hash); + }, + [&] { + node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider)); + }, + [&] { + const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider); + if (!service_opt) { + return; + } + node.SetAddrLocal(*service_opt); + }, + [&] { + const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + bool complete; + node.ReceiveMsgBytes(b, complete); + }); } (void)node.GetAddrLocal(); @@ -138,14 +107,12 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)node.GetId(); (void)node.GetLocalNonce(); (void)node.GetLocalServices(); - (void)node.GetMyStartingHeight(); const int ref_count = node.GetRefCount(); assert(ref_count >= 0); (void)node.GetCommonVersion(); (void)node.RelayAddrsWithConn(); - const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ? - fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL}) : - static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>()); + const NetPermissionFlags net_permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS); (void)node.HasPermission(net_permission_flags); + (void)node.ConnectedThroughNetwork(); } diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp index 8a674ac1e9..544a33047b 100644 --- a/src/test/fuzz/net_permissions.cpp +++ b/src/test/fuzz/net_permissions.cpp @@ -13,22 +13,11 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(net_permissions) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(32); - const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ? fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({ - NetPermissionFlags::PF_NONE, - NetPermissionFlags::PF_BLOOMFILTER, - NetPermissionFlags::PF_RELAY, - NetPermissionFlags::PF_FORCERELAY, - NetPermissionFlags::PF_NOBAN, - NetPermissionFlags::PF_MEMPOOL, - NetPermissionFlags::PF_ADDR, - NetPermissionFlags::PF_ISIMPLICIT, - NetPermissionFlags::PF_ALL, - }) : - static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>()); + const NetPermissionFlags net_permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS); NetWhitebindPermissions net_whitebind_permissions; bilingual_str error_net_whitebind_permissions; diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp index 8252f38726..6e9bb47ff6 100644 --- a/src/test/fuzz/netaddress.cpp +++ b/src/test/fuzz/netaddress.cpp @@ -12,7 +12,7 @@ #include <netinet/in.h> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(netaddress) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp new file mode 100644 index 0000000000..aaebe83c0a --- /dev/null +++ b/src/test/fuzz/node_eviction.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <net.h> +#include <optional.h> +#include <protocol.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <optional> +#include <vector> + +FUZZ_TARGET(node_eviction) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + std::vector<NodeEvictionCandidate> eviction_candidates; + while (fuzzed_data_provider.ConsumeBool()) { + eviction_candidates.push_back({ + fuzzed_data_provider.ConsumeIntegral<NodeId>(), + fuzzed_data_provider.ConsumeIntegral<int64_t>(), + fuzzed_data_provider.ConsumeIntegral<int64_t>(), + fuzzed_data_provider.ConsumeIntegral<int64_t>(), + fuzzed_data_provider.ConsumeIntegral<int64_t>(), + fuzzed_data_provider.ConsumeBool(), + fuzzed_data_provider.ConsumeBool(), + fuzzed_data_provider.ConsumeBool(), + fuzzed_data_provider.ConsumeIntegral<uint64_t>(), + fuzzed_data_provider.ConsumeBool(), + fuzzed_data_provider.ConsumeBool(), + }); + } + // Make a copy since eviction_candidates may be in some valid but otherwise + // indeterminate state after the SelectNodeToEvict(&&) call. + const std::vector<NodeEvictionCandidate> eviction_candidates_copy = eviction_candidates; + const Optional<NodeId> node_to_evict = SelectNodeToEvict(std::move(eviction_candidates)); + if (node_to_evict) { + assert(std::any_of(eviction_candidates_copy.begin(), eviction_candidates_copy.end(), [&node_to_evict](const NodeEvictionCandidate& eviction_candidate) { return *node_to_evict == eviction_candidate.id; })); + } +} diff --git a/src/test/fuzz/p2p_transport_deserializer.cpp b/src/test/fuzz/p2p_transport_deserializer.cpp index 7e216e16fe..163f1b839e 100644 --- a/src/test/fuzz/p2p_transport_deserializer.cpp +++ b/src/test/fuzz/p2p_transport_deserializer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,24 +12,21 @@ #include <limits> #include <vector> -void initialize() +void initialize_p2p_transport_deserializer() { SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(p2p_transport_deserializer, initialize_p2p_transport_deserializer) { // Construct deserializer, with a dummy NodeId V1TransportDeserializer deserializer{Params(), (NodeId)0, SER_NETWORK, INIT_PROTO_VERSION}; - const char* pch = (const char*)buffer.data(); - size_t n_bytes = buffer.size(); - while (n_bytes > 0) { - const int handled = deserializer.Read(pch, n_bytes); + Span<const uint8_t> msg_bytes{buffer}; + while (msg_bytes.size() > 0) { + const int handled = deserializer.Read(msg_bytes); if (handled < 0) { break; } - pch += handled; - n_bytes -= handled; if (deserializer.Complete()) { const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()}; uint32_t out_err_raw_size{0}; diff --git a/src/test/fuzz/parse_hd_keypath.cpp b/src/test/fuzz/parse_hd_keypath.cpp index f668ca8c48..411b70230a 100644 --- a/src/test/fuzz/parse_hd_keypath.cpp +++ b/src/test/fuzz/parse_hd_keypath.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,7 +10,7 @@ #include <cstdint> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(parse_hd_keypath) { const std::string keypath_str(buffer.begin(), buffer.end()); std::vector<uint32_t> keypath; diff --git a/src/test/fuzz/parse_iso8601.cpp b/src/test/fuzz/parse_iso8601.cpp index c86f8a853e..dcb24ac127 100644 --- a/src/test/fuzz/parse_iso8601.cpp +++ b/src/test/fuzz/parse_iso8601.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,7 +11,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(parse_iso8601) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/parse_numbers.cpp b/src/test/fuzz/parse_numbers.cpp index 59f89dc9fb..ddd2bcfba3 100644 --- a/src/test/fuzz/parse_numbers.cpp +++ b/src/test/fuzz/parse_numbers.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,7 +8,7 @@ #include <string> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(parse_numbers) { const std::string random_string(buffer.begin(), buffer.end()); diff --git a/src/test/fuzz/parse_script.cpp b/src/test/fuzz/parse_script.cpp index 21ac1aecf3..060ad3db12 100644 --- a/src/test/fuzz/parse_script.cpp +++ b/src/test/fuzz/parse_script.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,7 +6,7 @@ #include <script/script.h> #include <test/fuzz/fuzz.h> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(parse_script) { const std::string script_string(buffer.begin(), buffer.end()); try { diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp index a269378607..afe382ba21 100644 --- a/src/test/fuzz/parse_univalue.cpp +++ b/src/test/fuzz/parse_univalue.cpp @@ -12,13 +12,13 @@ #include <limits> #include <string> -void initialize() +void initialize_parse_univalue() { static const ECCVerifyHandle verify_handle; SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue) { const std::string random_string(buffer.begin(), buffer.end()); bool valid = true; diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp index 6c94a47f3c..fff893fb3f 100644 --- a/src/test/fuzz/policy_estimator.cpp +++ b/src/test/fuzz/policy_estimator.cpp @@ -14,62 +14,58 @@ #include <string> #include <vector> -void initialize() +void initialize_policy_estimator() { - InitializeFuzzingContext(); + static const auto testing_setup = MakeFuzzingContext<>(); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CBlockPolicyEstimator block_policy_estimator; while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3)) { - case 0: { - const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); - if (!mtx) { - break; - } - const CTransaction tx{*mtx}; - block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool()); - if (fuzzed_data_provider.ConsumeBool()) { - (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool()); - } - break; - } - case 1: { - std::vector<CTxMemPoolEntry> mempool_entries; - while (fuzzed_data_provider.ConsumeBool()) { + CallOneOf( + fuzzed_data_provider, + [&] { const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); if (!mtx) { - break; + return; } const CTransaction tx{*mtx}; - mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx)); - } - std::vector<const CTxMemPoolEntry*> ptrs; - ptrs.reserve(mempool_entries.size()); - for (const CTxMemPoolEntry& mempool_entry : mempool_entries) { - ptrs.push_back(&mempool_entry); - } - block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs); - break; - } - case 2: { - (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool()); - break; - } - case 3: { - block_policy_estimator.FlushUnconfirmed(); - break; - } - } + block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool()); + if (fuzzed_data_provider.ConsumeBool()) { + (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + } + }, + [&] { + std::vector<CTxMemPoolEntry> mempool_entries; + while (fuzzed_data_provider.ConsumeBool()) { + const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); + if (!mtx) { + break; + } + const CTransaction tx{*mtx}; + mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx)); + } + std::vector<const CTxMemPoolEntry*> ptrs; + ptrs.reserve(mempool_entries.size()); + for (const CTxMemPoolEntry& mempool_entry : mempool_entries) { + ptrs.push_back(&mempool_entry); + } + block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs); + }, + [&] { + (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool()); + }, + [&] { + block_policy_estimator.FlushUnconfirmed(); + }); (void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>()); EstimationResult result; - (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}), fuzzed_data_provider.ConsumeBool() ? &result : nullptr); + (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS), fuzzed_data_provider.ConsumeBool() ? &result : nullptr); FeeCalculation fee_calculation; (void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool()); - (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE})); + (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS)); } { FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider); diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp index 0edcf201c7..73242870a0 100644 --- a/src/test/fuzz/policy_estimator_io.cpp +++ b/src/test/fuzz/policy_estimator_io.cpp @@ -10,12 +10,12 @@ #include <cstdint> #include <vector> -void initialize() +void initialize_policy_estimator_io() { - InitializeFuzzingContext(); + static const auto testing_setup = MakeFuzzingContext<>(); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider); diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp index b7fc72373d..c4348495bf 100644 --- a/src/test/fuzz/pow.cpp +++ b/src/test/fuzz/pow.cpp @@ -15,12 +15,12 @@ #include <string> #include <vector> -void initialize() +void initialize_pow() { SelectParams(CBaseChainParams::MAIN); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(pow, initialize_pow) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const Consensus::Params& consensus_params = Params().GetConsensus(); @@ -43,7 +43,10 @@ void test_one_input(const std::vector<uint8_t>& buffer) current_block.nHeight = current_height; } if (fuzzed_data_provider.ConsumeBool()) { - current_block.nTime = fixed_time + current_height * consensus_params.nPowTargetSpacing; + const uint32_t seconds = current_height * consensus_params.nPowTargetSpacing; + if (!AdditionOverflow(fixed_time, seconds)) { + current_block.nTime = fixed_time + seconds; + } } if (fuzzed_data_provider.ConsumeBool()) { current_block.nBits = fixed_bits; diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp index 626e187cbd..51956bbe9e 100644 --- a/src/test/fuzz/prevector.cpp +++ b/src/test/fuzz/prevector.cpp @@ -204,7 +204,7 @@ public: } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(prevector) { FuzzedDataProvider prov(buffer.data(), buffer.size()); prevector_tester<8, int> test; diff --git a/src/test/fuzz/primitives_transaction.cpp b/src/test/fuzz/primitives_transaction.cpp index 4a0f920f58..48815c8910 100644 --- a/src/test/fuzz/primitives_transaction.cpp +++ b/src/test/fuzz/primitives_transaction.cpp @@ -12,7 +12,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(primitives_transaction) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const CScript script = ConsumeScript(fuzzed_data_provider); diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 3ef03137ec..e7cc0f5297 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -13,9 +13,11 @@ #include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> #include <test/util/mining.h> #include <test/util/net.h> #include <test/util/setup_common.h> +#include <test/util/validation.h> #include <util/memory.h> #include <validationinterface.h> #include <version.h> @@ -31,55 +33,81 @@ #include <vector> namespace { - -#ifdef MESSAGE_TYPE -#define TO_STRING_(s) #s -#define TO_STRING(s) TO_STRING_(s) -const std::string LIMIT_TO_MESSAGE_TYPE{TO_STRING(MESSAGE_TYPE)}; -#else -const std::string LIMIT_TO_MESSAGE_TYPE; -#endif - const TestingSetup* g_setup; } // namespace -void initialize() +void initialize_process_message() { - static TestingSetup setup{ - CBaseChainParams::REGTEST, - { - "-nodebuglogfile", - }, - }; - g_setup = &setup; - + static const auto testing_setup = MakeFuzzingContext<const TestingSetup>(); + g_setup = testing_setup.get(); for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { MineBlock(g_setup->m_node, CScript() << OP_TRUE); } SyncWithValidationInterfaceQueue(); } -void test_one_input(const std::vector<uint8_t>& buffer) +void fuzz_target(const std::vector<uint8_t>& buffer, const std::string& LIMIT_TO_MESSAGE_TYPE) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get(); + TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate(); + SetMockTime(1610000000); // any time to successfully reset ibd + chainstate.ResetIbd(); + const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()}; if (!LIMIT_TO_MESSAGE_TYPE.empty() && random_message_type != LIMIT_TO_MESSAGE_TYPE) { return; } - CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION}; - CNode& p2p_node = *MakeUnique<CNode>(0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY).release(); - p2p_node.fSuccessfullyConnected = true; - p2p_node.nVersion = PROTOCOL_VERSION; - p2p_node.SetCommonVersion(PROTOCOL_VERSION); + CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider).release(); + + const bool successfully_connected{true}; + p2p_node.fSuccessfullyConnected = successfully_connected; connman.AddTestNode(p2p_node); g_setup->m_node.peerman->InitializeNode(&p2p_node); + FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected); + + const auto mock_time = ConsumeTime(fuzzed_data_provider); + SetMockTime(mock_time); + + // fuzzed_data_provider is fully consumed after this call, don't use it + CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION}; try { g_setup->m_node.peerman->ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream, - GetTime<std::chrono::microseconds>(), std::atomic<bool>{false}); + GetTime<std::chrono::microseconds>(), std::atomic<bool>{false}); } catch (const std::ios_base::failure&) { } + { + LOCK(p2p_node.cs_sendProcessing); + g_setup->m_node.peerman->SendMessages(&p2p_node); + } SyncWithValidationInterfaceQueue(); LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement g_setup->m_node.connman->StopNodes(); } + +FUZZ_TARGET_INIT(process_message, initialize_process_message) { fuzz_target(buffer, ""); } +FUZZ_TARGET_INIT(process_message_addr, initialize_process_message) { fuzz_target(buffer, "addr"); } +FUZZ_TARGET_INIT(process_message_block, initialize_process_message) { fuzz_target(buffer, "block"); } +FUZZ_TARGET_INIT(process_message_blocktxn, initialize_process_message) { fuzz_target(buffer, "blocktxn"); } +FUZZ_TARGET_INIT(process_message_cmpctblock, initialize_process_message) { fuzz_target(buffer, "cmpctblock"); } +FUZZ_TARGET_INIT(process_message_feefilter, initialize_process_message) { fuzz_target(buffer, "feefilter"); } +FUZZ_TARGET_INIT(process_message_filteradd, initialize_process_message) { fuzz_target(buffer, "filteradd"); } +FUZZ_TARGET_INIT(process_message_filterclear, initialize_process_message) { fuzz_target(buffer, "filterclear"); } +FUZZ_TARGET_INIT(process_message_filterload, initialize_process_message) { fuzz_target(buffer, "filterload"); } +FUZZ_TARGET_INIT(process_message_getaddr, initialize_process_message) { fuzz_target(buffer, "getaddr"); } +FUZZ_TARGET_INIT(process_message_getblocks, initialize_process_message) { fuzz_target(buffer, "getblocks"); } +FUZZ_TARGET_INIT(process_message_getblocktxn, initialize_process_message) { fuzz_target(buffer, "getblocktxn"); } +FUZZ_TARGET_INIT(process_message_getdata, initialize_process_message) { fuzz_target(buffer, "getdata"); } +FUZZ_TARGET_INIT(process_message_getheaders, initialize_process_message) { fuzz_target(buffer, "getheaders"); } +FUZZ_TARGET_INIT(process_message_headers, initialize_process_message) { fuzz_target(buffer, "headers"); } +FUZZ_TARGET_INIT(process_message_inv, initialize_process_message) { fuzz_target(buffer, "inv"); } +FUZZ_TARGET_INIT(process_message_mempool, initialize_process_message) { fuzz_target(buffer, "mempool"); } +FUZZ_TARGET_INIT(process_message_notfound, initialize_process_message) { fuzz_target(buffer, "notfound"); } +FUZZ_TARGET_INIT(process_message_ping, initialize_process_message) { fuzz_target(buffer, "ping"); } +FUZZ_TARGET_INIT(process_message_pong, initialize_process_message) { fuzz_target(buffer, "pong"); } +FUZZ_TARGET_INIT(process_message_sendcmpct, initialize_process_message) { fuzz_target(buffer, "sendcmpct"); } +FUZZ_TARGET_INIT(process_message_sendheaders, initialize_process_message) { fuzz_target(buffer, "sendheaders"); } +FUZZ_TARGET_INIT(process_message_tx, initialize_process_message) { fuzz_target(buffer, "tx"); } +FUZZ_TARGET_INIT(process_message_verack, initialize_process_message) { fuzz_target(buffer, "verack"); } +FUZZ_TARGET_INIT(process_message_version, initialize_process_message) { fuzz_target(buffer, "version"); } diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index f722eeac3a..810f0aac92 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -12,47 +12,45 @@ #include <test/util/mining.h> #include <test/util/net.h> #include <test/util/setup_common.h> +#include <test/util/validation.h> #include <util/memory.h> #include <validation.h> #include <validationinterface.h> +namespace { const TestingSetup* g_setup; +} // namespace -void initialize() +void initialize_process_messages() { - static TestingSetup setup{ - CBaseChainParams::REGTEST, - { - "-nodebuglogfile", - }, - }; - g_setup = &setup; - + static const auto testing_setup = MakeFuzzingContext<const TestingSetup>(); + g_setup = testing_setup.get(); for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { MineBlock(g_setup->m_node, CScript() << OP_TRUE); } SyncWithValidationInterfaceQueue(); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(process_messages, initialize_process_messages) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get(); - std::vector<CNode*> peers; + TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate(); + SetMockTime(1610000000); // any time to successfully reset ibd + chainstate.ResetIbd(); + std::vector<CNode*> peers; const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3); for (int i = 0; i < num_peers_to_add; ++i) { - const ServiceFlags service_flags = ServiceFlags(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); - const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH}); - peers.push_back(MakeUnique<CNode>(i, service_flags, 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, conn_type).release()); + peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release()); CNode& p2p_node = *peers.back(); - p2p_node.fSuccessfullyConnected = true; + const bool successfully_connected{true}; + p2p_node.fSuccessfullyConnected = successfully_connected; p2p_node.fPauseSend = false; - p2p_node.nVersion = PROTOCOL_VERSION; - p2p_node.SetCommonVersion(PROTOCOL_VERSION); g_setup->m_node.peerman->InitializeNode(&p2p_node); + FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected); connman.AddTestNode(p2p_node); } @@ -60,6 +58,9 @@ void test_one_input(const std::vector<uint8_t>& buffer) while (fuzzed_data_provider.ConsumeBool()) { const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()}; + const auto mock_time = ConsumeTime(fuzzed_data_provider); + SetMockTime(mock_time); + CSerializedNetMsg net_msg; net_msg.m_type = random_message_type; net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider); @@ -73,6 +74,10 @@ void test_one_input(const std::vector<uint8_t>& buffer) connman.ProcessMessagesOnce(random_node); } catch (const std::ios_base::failure&) { } + { + LOCK(random_node.cs_sendProcessing); + g_setup->m_node.peerman->SendMessages(&random_node); + } } SyncWithValidationInterfaceQueue(); LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement diff --git a/src/test/fuzz/protocol.cpp b/src/test/fuzz/protocol.cpp index 78df0f89e7..572181366b 100644 --- a/src/test/fuzz/protocol.cpp +++ b/src/test/fuzz/protocol.cpp @@ -12,7 +12,7 @@ #include <stdexcept> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(protocol) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::optional<CInv> inv = ConsumeDeserializable<CInv>(fuzzed_data_provider); diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp index 908e2b16f2..0b4588c4ce 100644 --- a/src/test/fuzz/psbt.cpp +++ b/src/test/fuzz/psbt.cpp @@ -17,12 +17,12 @@ #include <string> #include <vector> -void initialize() +void initialize_psbt() { static const ECCVerifyHandle verify_handle; } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(psbt, initialize_psbt) { PartiallySignedTransaction psbt_mut; const std::string raw_psbt{buffer.begin(), buffer.end()}; diff --git a/src/test/fuzz/random.cpp b/src/test/fuzz/random.cpp index 7df6594ad6..96668734fd 100644 --- a/src/test/fuzz/random.cpp +++ b/src/test/fuzz/random.cpp @@ -12,7 +12,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(random) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp index 1fd88a5f7b..26c89a70c3 100644 --- a/src/test/fuzz/rbf.cpp +++ b/src/test/fuzz/rbf.cpp @@ -15,9 +15,10 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(rbf) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + SetMockTime(ConsumeTime(fuzzed_data_provider)); std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); if (!mtx) { return; diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp index 623b8cff3a..2a08b45aa3 100644 --- a/src/test/fuzz/rolling_bloom_filter.cpp +++ b/src/test/fuzz/rolling_bloom_filter.cpp @@ -14,7 +14,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(rolling_bloom_filter) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); @@ -22,29 +22,27 @@ void test_one_input(const std::vector<uint8_t>& buffer) fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, 1000), 0.999 / fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, std::numeric_limits<unsigned int>::max())}; while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 2)) { - case 0: { - const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); - (void)rolling_bloom_filter.contains(b); - rolling_bloom_filter.insert(b); - const bool present = rolling_bloom_filter.contains(b); - assert(present); - break; - } - case 1: { - const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider); - if (!u256) { - break; - } - (void)rolling_bloom_filter.contains(*u256); - rolling_bloom_filter.insert(*u256); - const bool present = rolling_bloom_filter.contains(*u256); - assert(present); - break; - } - case 2: - rolling_bloom_filter.reset(); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + (void)rolling_bloom_filter.contains(b); + rolling_bloom_filter.insert(b); + const bool present = rolling_bloom_filter.contains(b); + assert(present); + }, + [&] { + const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider); + if (!u256) { + return; + } + (void)rolling_bloom_filter.contains(*u256); + rolling_bloom_filter.insert(*u256); + const bool present = rolling_bloom_filter.contains(*u256); + assert(present); + }, + [&] { + rolling_bloom_filter.reset(); + }); } } diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 4274fa4351..7fadf36f98 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -29,7 +29,7 @@ #include <string> #include <vector> -void initialize() +void initialize_script() { // Fuzzers using pubkey must hold an ECCVerifyHandle. static const ECCVerifyHandle verify_handle; @@ -37,7 +37,7 @@ void initialize() SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(script, initialize_script) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::optional<CScript> script_opt = ConsumeDeserializable<CScript>(fuzzed_data_provider); @@ -71,7 +71,22 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)IsSolvable(signing_provider, script); TxoutType which_type; - (void)IsStandard(script, which_type); + bool is_standard_ret = IsStandard(script, which_type); + if (!is_standard_ret) { + assert(which_type == TxoutType::NONSTANDARD || + which_type == TxoutType::NULL_DATA || + which_type == TxoutType::MULTISIG); + } + if (which_type == TxoutType::NONSTANDARD) { + assert(!is_standard_ret); + } + if (which_type == TxoutType::NULL_DATA) { + assert(script.IsUnspendable()); + } + if (script.IsUnspendable()) { + assert(which_type == TxoutType::NULL_DATA || + which_type == TxoutType::NONSTANDARD); + } (void)RecursiveDynamicUsage(script); @@ -82,7 +97,6 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)script.IsPayToScriptHash(); (void)script.IsPayToWitnessScriptHash(); (void)script.IsPushOnly(); - (void)script.IsUnspendable(); (void)script.GetSigOpCount(/* fAccurate= */ false); (void)FormatScript(script); @@ -140,13 +154,13 @@ void test_one_input(const std::vector<uint8_t>& buffer) { WitnessUnknown witness_unknown_1{}; - witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<int>(); + witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40); witness_unknown_1.length = witness_unknown_program_1.size(); std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown_1.program); WitnessUnknown witness_unknown_2{}; - witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<int>(); + witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); const std::vector<uint8_t> witness_unknown_program_2 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40); witness_unknown_2.length = witness_unknown_program_2.size(); std::copy(witness_unknown_program_2.begin(), witness_unknown_program_2.end(), witness_unknown_2.program); diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp new file mode 100644 index 0000000000..2091ad5d91 --- /dev/null +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -0,0 +1,200 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <test/fuzz/fuzz.h> + +#include <primitives/transaction.h> +#include <pubkey.h> +#include <script/interpreter.h> +#include <serialize.h> +#include <streams.h> +#include <univalue.h> +#include <util/strencodings.h> + +#include <boost/algorithm/string.hpp> +#include <cstdint> +#include <string> +#include <vector> + +// This fuzz "test" can be used to minimize test cases for script_assets_test in +// src/test/script_tests.cpp. While it written as a fuzz test, and can be used as such, +// fuzzing the inputs is unlikely to construct useful test cases. +// +// Instead, it is primarily intended to be run on a test set that was generated +// externally, for example using test/functional/feature_taproot.py's --dumptests mode. +// The minimized set can then be concatenated together, surrounded by '[' and ']', +// and used as the script_assets_test.json input to the script_assets_test unit test: +// +// (normal build) +// $ mkdir dump +// $ for N in $(seq 1 10); do TEST_DUMP_DIR=dump test/functional/feature_taproot --dumptests; done +// $ ... +// +// (fuzz test build) +// $ mkdir dump-min +// $ ./src/test/fuzz/script_assets_test_minimizer -merge=1 dump-min/ dump/ +// $ (echo -en '[\n'; cat dump-min/* | head -c -2; echo -en '\n]') >script_assets_test.json + +namespace { + +std::vector<unsigned char> CheckedParseHex(const std::string& str) +{ + if (str.size() && !IsHex(str)) throw std::runtime_error("Non-hex input '" + str + "'"); + return ParseHex(str); +} + +CScript ScriptFromHex(const std::string& str) +{ + std::vector<unsigned char> data = CheckedParseHex(str); + return CScript(data.begin(), data.end()); +} + +CMutableTransaction TxFromHex(const std::string& str) +{ + CMutableTransaction tx; + try { + VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, CheckedParseHex(str), 0) >> tx; + } catch (const std::ios_base::failure&) { + throw std::runtime_error("Tx deserialization failure"); + } + return tx; +} + +std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue) +{ + if (!univalue.isArray()) throw std::runtime_error("Prevouts must be array"); + std::vector<CTxOut> prevouts; + for (size_t i = 0; i < univalue.size(); ++i) { + CTxOut txout; + try { + VectorReader(SER_DISK, 0, CheckedParseHex(univalue[i].get_str()), 0) >> txout; + } catch (const std::ios_base::failure&) { + throw std::runtime_error("Prevout invalid format"); + } + prevouts.push_back(std::move(txout)); + } + return prevouts; +} + +CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue) +{ + if (!univalue.isArray()) throw std::runtime_error("Script witness is not array"); + CScriptWitness scriptwitness; + for (size_t i = 0; i < univalue.size(); ++i) { + auto bytes = CheckedParseHex(univalue[i].get_str()); + scriptwitness.stack.push_back(std::move(bytes)); + } + return scriptwitness; +} + +const std::map<std::string, unsigned int> FLAG_NAMES = { + {std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH}, + {std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG}, + {std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY}, + {std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY}, + {std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY}, + {std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS}, + {std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT}, +}; + +std::vector<unsigned int> AllFlags() +{ + std::vector<unsigned int> ret; + + for (unsigned int i = 0; i < 128; ++i) { + unsigned int flag = 0; + if (i & 1) flag |= SCRIPT_VERIFY_P2SH; + if (i & 2) flag |= SCRIPT_VERIFY_DERSIG; + if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY; + if (i & 8) flag |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + if (i & 16) flag |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; + if (i & 32) flag |= SCRIPT_VERIFY_WITNESS; + if (i & 64) flag |= SCRIPT_VERIFY_TAPROOT; + + // SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH + if (flag & SCRIPT_VERIFY_WITNESS && !(flag & SCRIPT_VERIFY_P2SH)) continue; + // SCRIPT_VERIFY_TAPROOT requires SCRIPT_VERIFY_WITNESS + if (flag & SCRIPT_VERIFY_TAPROOT && !(flag & SCRIPT_VERIFY_WITNESS)) continue; + + ret.push_back(flag); + } + + return ret; +} + +const std::vector<unsigned int> ALL_FLAGS = AllFlags(); + +unsigned int ParseScriptFlags(const std::string& str) +{ + if (str.empty()) return 0; + + unsigned int flags = 0; + std::vector<std::string> words; + boost::algorithm::split(words, str, boost::algorithm::is_any_of(",")); + + for (const std::string& word : words) + { + auto it = FLAG_NAMES.find(word); + if (it == FLAG_NAMES.end()) throw std::runtime_error("Unknown verification flag " + word); + flags |= it->second; + } + + return flags; +} + +void Test(const std::string& str) +{ + UniValue test; + if (!test.read(str) || !test.isObject()) throw std::runtime_error("Non-object test input"); + + CMutableTransaction tx = TxFromHex(test["tx"].get_str()); + const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]); + if (prevouts.size() != tx.vin.size()) throw std::runtime_error("Incorrect number of prevouts"); + size_t idx = test["index"].get_int64(); + if (idx >= tx.vin.size()) throw std::runtime_error("Invalid index"); + unsigned int test_flags = ParseScriptFlags(test["flags"].get_str()); + bool final = test.exists("final") && test["final"].get_bool(); + + if (test.exists("success")) { + tx.vin[idx].scriptSig = ScriptFromHex(test["success"]["scriptSig"].get_str()); + tx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["success"]["witness"]); + PrecomputedTransactionData txdata; + txdata.Init(tx, std::vector<CTxOut>(prevouts)); + MutableTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, txdata); + for (const auto flags : ALL_FLAGS) { + // "final": true tests are valid for all flags. Others are only valid with flags that are + // a subset of test_flags. + if (final || ((flags & test_flags) == flags)) { + (void)VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr); + } + } + } + + if (test.exists("failure")) { + tx.vin[idx].scriptSig = ScriptFromHex(test["failure"]["scriptSig"].get_str()); + tx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["failure"]["witness"]); + PrecomputedTransactionData txdata; + txdata.Init(tx, std::vector<CTxOut>(prevouts)); + MutableTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, txdata); + for (const auto flags : ALL_FLAGS) { + // If a test is supposed to fail with test_flags, it should also fail with any superset thereof. + if ((flags & test_flags) == test_flags) { + (void)VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr); + } + } + } +} + +ECCVerifyHandle handle; + +} // namespace + +FUZZ_TARGET(script_assets_test_minimizer) +{ + if (buffer.size() < 2 || buffer.back() != '\n' || buffer[buffer.size() - 2] != ',') return; + const std::string str((const char*)buffer.data(), buffer.size() - 2); + try { + Test(str); + } catch (const std::runtime_error&) {} +} diff --git a/src/test/fuzz/script_bitcoin_consensus.cpp b/src/test/fuzz/script_bitcoin_consensus.cpp index 22f4b4f44a..fcd66b234e 100644 --- a/src/test/fuzz/script_bitcoin_consensus.cpp +++ b/src/test/fuzz/script_bitcoin_consensus.cpp @@ -12,7 +12,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(script_bitcoin_consensus) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::vector<uint8_t> random_bytes_1 = ConsumeRandomLengthByteVector(fuzzed_data_provider); diff --git a/src/test/fuzz/script_descriptor_cache.cpp b/src/test/fuzz/script_descriptor_cache.cpp index 4bfe61cec7..1c62c018e7 100644 --- a/src/test/fuzz/script_descriptor_cache.cpp +++ b/src/test/fuzz/script_descriptor_cache.cpp @@ -13,7 +13,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(script_descriptor_cache) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); DescriptorCache descriptor_cache; diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp index ffc65eedc0..ce8915ca2c 100644 --- a/src/test/fuzz/script_flags.cpp +++ b/src/test/fuzz/script_flags.cpp @@ -13,12 +13,12 @@ /** Flags that are not forbidden by an assert */ static bool IsValidFlagCombination(unsigned flags); -void initialize() +void initialize_script_flags() { static const ECCVerifyHandle verify_handle; } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(script_flags, initialize_script_flags) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); try { @@ -31,7 +31,6 @@ void test_one_input(const std::vector<uint8_t>& buffer) try { const CTransaction tx(deserialize, ds); - const PrecomputedTransactionData txdata(tx); unsigned int verify_flags; ds >> verify_flags; @@ -41,10 +40,17 @@ void test_one_input(const std::vector<uint8_t>& buffer) unsigned int fuzzed_flags; ds >> fuzzed_flags; + std::vector<CTxOut> spent_outputs; for (unsigned i = 0; i < tx.vin.size(); ++i) { CTxOut prevout; ds >> prevout; + spent_outputs.push_back(prevout); + } + PrecomputedTransactionData txdata; + txdata.Init(tx, std::move(spent_outputs)); + for (unsigned i = 0; i < tx.vin.size(); ++i) { + const CTxOut& prevout = txdata.m_spent_outputs.at(i); const TransactionSignatureChecker checker{&tx, i, prevout.nValue, txdata}; ScriptError serror; diff --git a/src/test/fuzz/script_interpreter.cpp b/src/test/fuzz/script_interpreter.cpp index 26d5732f24..5d59771682 100644 --- a/src/test/fuzz/script_interpreter.cpp +++ b/src/test/fuzz/script_interpreter.cpp @@ -15,7 +15,7 @@ bool CastToBool(const std::vector<unsigned char>& vch); -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(script_interpreter) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); { diff --git a/src/test/fuzz/script_ops.cpp b/src/test/fuzz/script_ops.cpp index 7d24af20ac..bdbfe817ff 100644 --- a/src/test/fuzz/script_ops.cpp +++ b/src/test/fuzz/script_ops.cpp @@ -11,61 +11,58 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(script_ops) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CScript script = ConsumeScript(fuzzed_data_provider); while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { - case 0: { - CScript s = ConsumeScript(fuzzed_data_provider); - script = std::move(s); - break; - } - case 1: { - const CScript& s = ConsumeScript(fuzzed_data_provider); - script = s; - break; - } - case 2: - script << fuzzed_data_provider.ConsumeIntegral<int64_t>(); - break; - case 3: - script << ConsumeOpcodeType(fuzzed_data_provider); - break; - case 4: - script << ConsumeScriptNum(fuzzed_data_provider); - break; - case 5: - script << ConsumeRandomLengthByteVector(fuzzed_data_provider); - break; - case 6: - script.clear(); - break; - case 7: { - (void)script.GetSigOpCount(false); - (void)script.GetSigOpCount(true); - (void)script.GetSigOpCount(script); - (void)script.HasValidOps(); - (void)script.IsPayToScriptHash(); - (void)script.IsPayToWitnessScriptHash(); - (void)script.IsPushOnly(); - (void)script.IsUnspendable(); - { - CScript::const_iterator pc = script.begin(); - opcodetype opcode; - (void)script.GetOp(pc, opcode); - std::vector<uint8_t> data; - (void)script.GetOp(pc, opcode, data); - (void)script.IsPushOnly(pc); - } - { - int version; - std::vector<uint8_t> program; - (void)script.IsWitnessProgram(version, program); - } - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + CScript s = ConsumeScript(fuzzed_data_provider); + script = std::move(s); + }, + [&] { + const CScript& s = ConsumeScript(fuzzed_data_provider); + script = s; + }, + [&] { + script << fuzzed_data_provider.ConsumeIntegral<int64_t>(); + }, + [&] { + script << ConsumeOpcodeType(fuzzed_data_provider); + }, + [&] { + script << ConsumeScriptNum(fuzzed_data_provider); + }, + [&] { + script << ConsumeRandomLengthByteVector(fuzzed_data_provider); + }, + [&] { + script.clear(); + }, + [&] { + (void)script.GetSigOpCount(false); + (void)script.GetSigOpCount(true); + (void)script.GetSigOpCount(script); + (void)script.HasValidOps(); + (void)script.IsPayToScriptHash(); + (void)script.IsPayToWitnessScriptHash(); + (void)script.IsPushOnly(); + (void)script.IsUnspendable(); + { + CScript::const_iterator pc = script.begin(); + opcodetype opcode; + (void)script.GetOp(pc, opcode); + std::vector<uint8_t> data; + (void)script.GetOp(pc, opcode, data); + (void)script.IsPushOnly(pc); + } + { + int version; + std::vector<uint8_t> program; + (void)script.IsWitnessProgram(version, program); + } + }); } } diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp index 434a47b702..f7e45d6889 100644 --- a/src/test/fuzz/script_sigcache.cpp +++ b/src/test/fuzz/script_sigcache.cpp @@ -16,7 +16,7 @@ #include <string> #include <vector> -void initialize() +void initialize_script_sigcache() { static const ECCVerifyHandle ecc_verify_handle; ECC_Start(); @@ -24,22 +24,30 @@ void initialize() InitSignatureCache(); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(script_sigcache, initialize_script_sigcache) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::optional<CMutableTransaction> mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider); - const CTransaction tx = mutable_transaction ? CTransaction{*mutable_transaction} : CTransaction{}; + const CTransaction tx{mutable_transaction ? *mutable_transaction : CMutableTransaction{}}; const unsigned int n_in = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); const CAmount amount = ConsumeMoney(fuzzed_data_provider); const bool store = fuzzed_data_provider.ConsumeBool(); PrecomputedTransactionData tx_data; CachingTransactionSignatureChecker caching_transaction_signature_checker{mutable_transaction ? &tx : nullptr, n_in, amount, store, tx_data}; - const std::optional<CPubKey> pub_key = ConsumeDeserializable<CPubKey>(fuzzed_data_provider); - if (pub_key) { - const std::vector<uint8_t> random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); - if (!random_bytes.empty()) { - (void)caching_transaction_signature_checker.VerifySignature(random_bytes, *pub_key, ConsumeUInt256(fuzzed_data_provider)); + if (fuzzed_data_provider.ConsumeBool()) { + const auto random_bytes = fuzzed_data_provider.ConsumeBytes<unsigned char>(64); + const XOnlyPubKey pub_key(ConsumeUInt256(fuzzed_data_provider)); + if (random_bytes.size() == 64) { + (void)caching_transaction_signature_checker.VerifySchnorrSignature(random_bytes, pub_key, ConsumeUInt256(fuzzed_data_provider)); + } + } else { + const auto random_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); + const auto pub_key = ConsumeDeserializable<CPubKey>(fuzzed_data_provider); + if (pub_key) { + if (!random_bytes.empty()) { + (void)caching_transaction_signature_checker.VerifyECDSASignature(random_bytes, *pub_key, ConsumeUInt256(fuzzed_data_provider)); + } } } } diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp index c626f950e7..fe850a6959 100644 --- a/src/test/fuzz/script_sign.cpp +++ b/src/test/fuzz/script_sign.cpp @@ -22,14 +22,14 @@ #include <string> #include <vector> -void initialize() +void initialize_script_sign() { static const ECCVerifyHandle ecc_verify_handle; ECC_Start(); SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(script_sign, initialize_script_sign) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::vector<uint8_t> key = ConsumeRandomLengthByteVector(fuzzed_data_provider, 128); diff --git a/src/test/fuzz/scriptnum_ops.cpp b/src/test/fuzz/scriptnum_ops.cpp index 68c1ae58ca..bc4867839c 100644 --- a/src/test/fuzz/scriptnum_ops.cpp +++ b/src/test/fuzz/scriptnum_ops.cpp @@ -24,110 +24,104 @@ bool IsValidSubtraction(const CScriptNum& lhs, const CScriptNum& rhs) } } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(scriptnum_ops) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); CScriptNum script_num = ConsumeScriptNum(fuzzed_data_provider); while (fuzzed_data_provider.remaining_bytes() > 0) { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) { - case 0: { - const int64_t i = fuzzed_data_provider.ConsumeIntegral<int64_t>(); - assert((script_num == i) != (script_num != i)); - assert((script_num <= i) != (script_num > i)); - assert((script_num >= i) != (script_num < i)); - // Avoid signed integer overflow: - // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long' - if (IsValidAddition(script_num, CScriptNum{i})) { - assert((script_num + i) - i == script_num); - } - // Avoid signed integer overflow: - // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long' - if (IsValidSubtraction(script_num, CScriptNum{i})) { - assert((script_num - i) + i == script_num); - } - break; - } - case 1: { - const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); - assert((script_num == random_script_num) != (script_num != random_script_num)); - assert((script_num <= random_script_num) != (script_num > random_script_num)); - assert((script_num >= random_script_num) != (script_num < random_script_num)); - // Avoid signed integer overflow: - // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long' - if (IsValidAddition(script_num, random_script_num)) { - assert((script_num + random_script_num) - random_script_num == script_num); - } - // Avoid signed integer overflow: - // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long' - if (IsValidSubtraction(script_num, random_script_num)) { - assert((script_num - random_script_num) + random_script_num == script_num); - } - break; - } - case 2: { - const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); - if (!IsValidAddition(script_num, random_script_num)) { - // Avoid assertion failure: - // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed. - break; - } - script_num += random_script_num; - break; - } - case 3: { - const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); - if (!IsValidSubtraction(script_num, random_script_num)) { - // Avoid assertion failure: - // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed. - break; - } - script_num -= random_script_num; - break; - } - case 4: - script_num = script_num & fuzzed_data_provider.ConsumeIntegral<int64_t>(); - break; - case 5: - script_num = script_num & ConsumeScriptNum(fuzzed_data_provider); - break; - case 6: - script_num &= ConsumeScriptNum(fuzzed_data_provider); - break; - case 7: - if (script_num == CScriptNum{std::numeric_limits<int64_t>::min()}) { - // Avoid assertion failure: - // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits<int64_t>::min()' failed. - break; - } - script_num = -script_num; - break; - case 8: - script_num = fuzzed_data_provider.ConsumeIntegral<int64_t>(); - break; - case 9: { - const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>(); - if (!IsValidAddition(script_num, CScriptNum{random_integer})) { - // Avoid assertion failure: - // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed. - break; - } - script_num += random_integer; - break; - } - case 10: { - const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>(); - if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) { - // Avoid assertion failure: - // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed. - break; - } - script_num -= random_integer; - break; - } - case 11: - script_num &= fuzzed_data_provider.ConsumeIntegral<int64_t>(); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + const int64_t i = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + assert((script_num == i) != (script_num != i)); + assert((script_num <= i) != (script_num > i)); + assert((script_num >= i) != (script_num < i)); + // Avoid signed integer overflow: + // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long' + if (IsValidAddition(script_num, CScriptNum{i})) { + assert((script_num + i) - i == script_num); + } + // Avoid signed integer overflow: + // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long' + if (IsValidSubtraction(script_num, CScriptNum{i})) { + assert((script_num - i) + i == script_num); + } + }, + [&] { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + assert((script_num == random_script_num) != (script_num != random_script_num)); + assert((script_num <= random_script_num) != (script_num > random_script_num)); + assert((script_num >= random_script_num) != (script_num < random_script_num)); + // Avoid signed integer overflow: + // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long' + if (IsValidAddition(script_num, random_script_num)) { + assert((script_num + random_script_num) - random_script_num == script_num); + } + // Avoid signed integer overflow: + // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long' + if (IsValidSubtraction(script_num, random_script_num)) { + assert((script_num - random_script_num) + random_script_num == script_num); + } + }, + [&] { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + if (!IsValidAddition(script_num, random_script_num)) { + // Avoid assertion failure: + // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed. + return; + } + script_num += random_script_num; + }, + [&] { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + if (!IsValidSubtraction(script_num, random_script_num)) { + // Avoid assertion failure: + // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed. + return; + } + script_num -= random_script_num; + }, + [&] { + script_num = script_num & fuzzed_data_provider.ConsumeIntegral<int64_t>(); + }, + [&] { + script_num = script_num & ConsumeScriptNum(fuzzed_data_provider); + }, + [&] { + script_num &= ConsumeScriptNum(fuzzed_data_provider); + }, + [&] { + if (script_num == CScriptNum{std::numeric_limits<int64_t>::min()}) { + // Avoid assertion failure: + // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits<int64_t>::min()' failed. + return; + } + script_num = -script_num; + }, + [&] { + script_num = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + }, + [&] { + const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + if (!IsValidAddition(script_num, CScriptNum{random_integer})) { + // Avoid assertion failure: + // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed. + return; + } + script_num += random_integer; + }, + [&] { + const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) { + // Avoid assertion failure: + // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed. + return; + } + script_num -= random_integer; + }, + [&] { + script_num &= fuzzed_data_provider.ConsumeIntegral<int64_t>(); + }); (void)script_num.getint(); (void)script_num.getvch(); } diff --git a/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp index d4f302a8d3..0435626356 100644 --- a/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp +++ b/src/test/fuzz/secp256k1_ec_seckey_import_export_der.cpp @@ -14,7 +14,7 @@ int ec_seckey_import_der(const secp256k1_context* ctx, unsigned char* out32, const unsigned char* seckey, size_t seckeylen); int ec_seckey_export_der(const secp256k1_context* ctx, unsigned char* seckey, size_t* seckeylen, const unsigned char* key32, bool compressed); -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(secp256k1_ec_seckey_import_export_der) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; secp256k1_context* secp256k1_context_sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); diff --git a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp index ed8c7aba89..f437d53b57 100644 --- a/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp +++ b/src/test/fuzz/secp256k1_ecdsa_signature_parse_der_lax.cpp @@ -14,7 +14,7 @@ bool SigHasLowR(const secp256k1_ecdsa_signature* sig); int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char* input, size_t inputlen); -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(secp256k1_ecdsa_signature_parse_der_lax) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; const std::vector<uint8_t> signature_bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp index 3aaeb66649..3e7b72805e 100644 --- a/src/test/fuzz/signature_checker.cpp +++ b/src/test/fuzz/signature_checker.cpp @@ -13,7 +13,7 @@ #include <string> #include <vector> -void initialize() +void initialize_signature_checker() { static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); } @@ -24,11 +24,16 @@ class FuzzedSignatureChecker : public BaseSignatureChecker FuzzedDataProvider& m_fuzzed_data_provider; public: - FuzzedSignatureChecker(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider(fuzzed_data_provider) + explicit FuzzedSignatureChecker(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider(fuzzed_data_provider) { } - bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override + bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override + { + return m_fuzzed_data_provider.ConsumeBool(); + } + + bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override { return m_fuzzed_data_provider.ConsumeBool(); } @@ -47,7 +52,7 @@ public: }; } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(signature_checker, initialize_signature_checker) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>(); diff --git a/src/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp index 786f1a83fe..83effec064 100644 --- a/src/test/fuzz/signet.cpp +++ b/src/test/fuzz/signet.cpp @@ -15,12 +15,12 @@ #include <optional> #include <vector> -void initialize() +void initialize_signet() { - InitializeFuzzingContext(CBaseChainParams::SIGNET); + static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::SIGNET); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(signet, initialize_signet) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; const std::optional<CBlock> block = ConsumeDeserializable<CBlock>(fuzzed_data_provider); diff --git a/src/test/fuzz/span.cpp b/src/test/fuzz/span.cpp index f6b6e8f6f0..8f753948df 100644 --- a/src/test/fuzz/span.cpp +++ b/src/test/fuzz/span.cpp @@ -13,7 +13,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(span) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); diff --git a/src/test/fuzz/spanparsing.cpp b/src/test/fuzz/spanparsing.cpp index e5bf5dd608..b8996632bc 100644 --- a/src/test/fuzz/spanparsing.cpp +++ b/src/test/fuzz/spanparsing.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -6,7 +6,7 @@ #include <test/fuzz/fuzz.h> #include <util/spanparsing.h> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(spanparsing) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const size_t query_size = fuzzed_data_provider.ConsumeIntegral<size_t>(); diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index 271062dc95..282a2cd8ca 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -33,7 +33,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(string) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::string random_string_1 = fuzzed_data_provider.ConsumeRandomLengthString(32); diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp index 29064bc45c..b66a7abfb3 100644 --- a/src/test/fuzz/strprintf.cpp +++ b/src/test/fuzz/strprintf.cpp @@ -4,6 +4,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> #include <tinyformat.h> #include <util/strencodings.h> #include <util/translation.h> @@ -13,7 +14,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(str_printf) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const std::string format_string = fuzzed_data_provider.ConsumeRandomLengthString(64); @@ -109,32 +110,32 @@ void test_one_input(const std::vector<uint8_t>& buffer) } try { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) { - case 0: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); - break; - case 1: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); - break; - case 2: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>()); - break; - case 3: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>()); - break; - case 4: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>()); - break; - case 5: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool()); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool()); + }); } catch (const tinyformat::format_error&) { } @@ -155,40 +156,40 @@ void test_one_input(const std::vector<uint8_t>& buffer) } try { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { - case 0: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>()); - break; - case 1: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>()); - break; - case 2: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>()); - break; - case 3: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>()); - break; - case 4: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>()); - break; - case 5: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); - break; - case 6: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>()); - break; - case 7: - (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>()); - (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>()); - break; - } + CallOneOf( + fuzzed_data_provider, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>()); + }, + [&] { + (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>()); + }); } catch (const tinyformat::format_error&) { } } diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp index 01b523cee4..47b38b6d23 100644 --- a/src/test/fuzz/system.cpp +++ b/src/test/fuzz/system.cpp @@ -22,7 +22,7 @@ std::string GetArgumentName(const std::string& name) } } // namespace -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(system) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); ArgsManager args_manager{}; @@ -32,71 +32,63 @@ void test_one_input(const std::vector<uint8_t>& buffer) } while (fuzzed_data_provider.ConsumeBool()) { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 7)) { - case 0: { - args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16)); - break; - } - case 1: { - args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); - break; - } - case 2: { - args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); - break; - } - case 3: { - args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool()); - break; - } - case 4: { - const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN}); - // Avoid hitting: - // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. - const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16)); - if (args_manager.GetArgFlags(argument_name) != nullopt) { - break; - } - args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>(), options_category); - break; - } - case 5: { - // Avoid hitting: - // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. - const std::vector<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider); - std::vector<std::string> hidden_arguments; - for (const std::string& name : names) { - const std::string hidden_argument = GetArgumentName(name); - if (args_manager.GetArgFlags(hidden_argument) != nullopt) { - continue; + CallOneOf( + fuzzed_data_provider, + [&] { + args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16)); + }, + [&] { + args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + }, + [&] { + args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16)); + }, + [&] { + args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool()); + }, + [&] { + const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN}); + // Avoid hitting: + // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. + const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16)); + if (args_manager.GetArgFlags(argument_name) != nullopt) { + return; } - if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) { - continue; + args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>(), options_category); + }, + [&] { + // Avoid hitting: + // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed. + const std::vector<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider); + std::vector<std::string> hidden_arguments; + for (const std::string& name : names) { + const std::string hidden_argument = GetArgumentName(name); + if (args_manager.GetArgFlags(hidden_argument) != nullopt) { + continue; + } + if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) { + continue; + } + hidden_arguments.push_back(hidden_argument); } - hidden_arguments.push_back(hidden_argument); - } - args_manager.AddHiddenArgs(hidden_arguments); - break; - } - case 6: { - args_manager.ClearArgs(); - break; - } - case 7: { - const std::vector<std::string> random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider); - std::vector<const char*> argv; - argv.reserve(random_arguments.size()); - for (const std::string& random_argument : random_arguments) { - argv.push_back(random_argument.c_str()); - } - try { - std::string error; - (void)args_manager.ParseParameters(argv.size(), argv.data(), error); - } catch (const std::logic_error&) { - } - break; - } - } + args_manager.AddHiddenArgs(hidden_arguments); + }, + [&] { + args_manager.ClearArgs(); + }, + [&] { + const std::vector<std::string> random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider); + std::vector<const char*> argv; + argv.reserve(random_arguments.size()); + for (const std::string& random_argument : random_arguments) { + argv.push_back(random_argument.c_str()); + } + try { + std::string error; + (void)args_manager.ParseParameters(argv.size(), argv.data(), error); + } catch (const std::logic_error&) { + } + }); } const std::string s1 = fuzzed_data_provider.ConsumeRandomLengthString(16); diff --git a/src/test/fuzz/timedata.cpp b/src/test/fuzz/timedata.cpp index a0e579a88f..d7fa66298a 100644 --- a/src/test/fuzz/timedata.cpp +++ b/src/test/fuzz/timedata.cpp @@ -11,7 +11,7 @@ #include <string> #include <vector> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(timedata) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const unsigned int max_size = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, 1000); diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index d6deb7fc3d..13ae450756 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -21,12 +21,12 @@ #include <cassert> -void initialize() +void initialize_transaction() { SelectParams(CBaseChainParams::REGTEST); } -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET_INIT(transaction, initialize_transaction) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); try { @@ -42,7 +42,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) return CTransaction(deserialize, ds); } catch (const std::ios_base::failure&) { valid_tx = false; - return CTransaction(); + return CTransaction{CMutableTransaction{}}; } }(); bool valid_mutable_tx = true; @@ -95,7 +95,8 @@ void test_one_input(const std::vector<uint8_t>& buffer) CCoinsView coins_view; const CCoinsViewCache coins_view_cache(&coins_view); - (void)AreInputsStandard(tx, coins_view_cache); + (void)AreInputsStandard(tx, coins_view_cache, false); + (void)AreInputsStandard(tx, coins_view_cache, true); (void)IsWitnessStandard(tx, coins_view_cache); UniValue u(UniValue::VOBJ); diff --git a/src/test/fuzz/tx_in.cpp b/src/test/fuzz/tx_in.cpp index 8e116537d1..f8247c1fa4 100644 --- a/src/test/fuzz/tx_in.cpp +++ b/src/test/fuzz/tx_in.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,7 +12,7 @@ #include <cassert> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(tx_in) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); CTxIn tx_in; diff --git a/src/test/fuzz/tx_out.cpp b/src/test/fuzz/tx_out.cpp index aa1338d5ba..39a50b6c80 100644 --- a/src/test/fuzz/tx_out.cpp +++ b/src/test/fuzz/tx_out.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,7 +10,7 @@ #include <test/fuzz/fuzz.h> #include <version.h> -void test_one_input(const std::vector<uint8_t>& buffer) +FUZZ_TARGET(tx_out) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); CTxOut tx_out; diff --git a/src/test/fuzz/txrequest.cpp b/src/test/fuzz/txrequest.cpp new file mode 100644 index 0000000000..72438ff2d7 --- /dev/null +++ b/src/test/fuzz/txrequest.cpp @@ -0,0 +1,374 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <crypto/common.h> +#include <crypto/sha256.h> +#include <crypto/siphash.h> +#include <primitives/transaction.h> +#include <test/fuzz/fuzz.h> +#include <txrequest.h> + +#include <bitset> +#include <cstdint> +#include <queue> +#include <vector> + +namespace { + +constexpr int MAX_TXHASHES = 16; +constexpr int MAX_PEERS = 16; + +//! Randomly generated GenTxids used in this test (length is MAX_TXHASHES). +uint256 TXHASHES[MAX_TXHASHES]; + +//! Precomputed random durations (positive and negative, each ~exponentially distributed). +std::chrono::microseconds DELAYS[256]; + +struct Initializer +{ + Initializer() + { + for (uint8_t txhash = 0; txhash < MAX_TXHASHES; txhash += 1) { + CSHA256().Write(&txhash, 1).Finalize(TXHASHES[txhash].begin()); + } + int i = 0; + // DELAYS[N] for N=0..15 is just N microseconds. + for (; i < 16; ++i) { + DELAYS[i] = std::chrono::microseconds{i}; + } + // DELAYS[N] for N=16..127 has randomly-looking but roughly exponentially increasing values up to + // 198.416453 seconds. + for (; i < 128; ++i) { + int diff_bits = ((i - 10) * 2) / 9; + uint64_t diff = 1 + (CSipHasher(0, 0).Write(i).Finalize() >> (64 - diff_bits)); + DELAYS[i] = DELAYS[i - 1] + std::chrono::microseconds{diff}; + } + // DELAYS[N] for N=128..255 are negative delays with the same magnitude as N=0..127. + for (; i < 256; ++i) { + DELAYS[i] = -DELAYS[255 - i]; + } + } +} g_initializer; + +/** Tester class for TxRequestTracker + * + * It includes a naive reimplementation of its behavior, for a limited set + * of MAX_TXHASHES distinct txids, and MAX_PEERS peer identifiers. + * + * All of the public member functions perform the same operation on + * an actual TxRequestTracker and on the state of the reimplementation. + * The output of GetRequestable is compared with the expected value + * as well. + * + * Check() calls the TxRequestTracker's sanity check, plus compares the + * output of the constant accessors (Size(), CountLoad(), CountTracked()) + * with expected values. + */ +class Tester +{ + //! TxRequestTracker object being tested. + TxRequestTracker m_tracker; + + //! States for txid/peer combinations in the naive data structure. + enum class State { + NOTHING, //!< Absence of this txid/peer combination + + // Note that this implementation does not distinguish between DELAYED/READY/BEST variants of CANDIDATE. + CANDIDATE, + REQUESTED, + COMPLETED, + }; + + //! Sequence numbers, incremented whenever a new CANDIDATE is added. + uint64_t m_current_sequence{0}; + + //! List of future 'events' (all inserted reqtimes/exptimes). This is used to implement AdvanceToEvent. + std::priority_queue<std::chrono::microseconds, std::vector<std::chrono::microseconds>, + std::greater<std::chrono::microseconds>> m_events; + + //! Information about a txhash/peer combination. + struct Announcement + { + std::chrono::microseconds m_time; + uint64_t m_sequence; + State m_state{State::NOTHING}; + bool m_preferred; + bool m_is_wtxid; + uint64_t m_priority; //!< Precomputed priority. + }; + + //! Information about all txhash/peer combination. + Announcement m_announcements[MAX_TXHASHES][MAX_PEERS]; + + //! The current time; can move forward and backward. + std::chrono::microseconds m_now{244466666}; + + //! Delete txhashes whose only announcements are COMPLETED. + void Cleanup(int txhash) + { + bool all_nothing = true; + for (int peer = 0; peer < MAX_PEERS; ++peer) { + const Announcement& ann = m_announcements[txhash][peer]; + if (ann.m_state != State::NOTHING) { + if (ann.m_state != State::COMPLETED) return; + all_nothing = false; + } + } + if (all_nothing) return; + for (int peer = 0; peer < MAX_PEERS; ++peer) { + m_announcements[txhash][peer].m_state = State::NOTHING; + } + } + + //! Find the current best peer to request from for a txhash (or -1 if none). + int GetSelected(int txhash) const + { + int ret = -1; + uint64_t ret_priority = 0; + for (int peer = 0; peer < MAX_PEERS; ++peer) { + const Announcement& ann = m_announcements[txhash][peer]; + // Return -1 if there already is a (non-expired) in-flight request. + if (ann.m_state == State::REQUESTED) return -1; + // If it's a viable candidate, see if it has lower priority than the best one so far. + if (ann.m_state == State::CANDIDATE && ann.m_time <= m_now) { + if (ret == -1 || ann.m_priority > ret_priority) { + std::tie(ret, ret_priority) = std::tie(peer, ann.m_priority); + } + } + } + return ret; + } + +public: + Tester() : m_tracker(true) {} + + std::chrono::microseconds Now() const { return m_now; } + + void AdvanceTime(std::chrono::microseconds offset) + { + m_now += offset; + while (!m_events.empty() && m_events.top() <= m_now) m_events.pop(); + } + + void AdvanceToEvent() + { + while (!m_events.empty() && m_events.top() <= m_now) m_events.pop(); + if (!m_events.empty()) { + m_now = m_events.top(); + m_events.pop(); + } + } + + void DisconnectedPeer(int peer) + { + // Apply to naive structure: all announcements for that peer are wiped. + for (int txhash = 0; txhash < MAX_TXHASHES; ++txhash) { + if (m_announcements[txhash][peer].m_state != State::NOTHING) { + m_announcements[txhash][peer].m_state = State::NOTHING; + Cleanup(txhash); + } + } + + // Call TxRequestTracker's implementation. + m_tracker.DisconnectedPeer(peer); + } + + void ForgetTxHash(int txhash) + { + // Apply to naive structure: all announcements for that txhash are wiped. + for (int peer = 0; peer < MAX_PEERS; ++peer) { + m_announcements[txhash][peer].m_state = State::NOTHING; + } + Cleanup(txhash); + + // Call TxRequestTracker's implementation. + m_tracker.ForgetTxHash(TXHASHES[txhash]); + } + + void ReceivedInv(int peer, int txhash, bool is_wtxid, bool preferred, std::chrono::microseconds reqtime) + { + // Apply to naive structure: if no announcement for txidnum/peer combination + // already, create a new CANDIDATE; otherwise do nothing. + Announcement& ann = m_announcements[txhash][peer]; + if (ann.m_state == State::NOTHING) { + ann.m_preferred = preferred; + ann.m_state = State::CANDIDATE; + ann.m_time = reqtime; + ann.m_is_wtxid = is_wtxid; + ann.m_sequence = m_current_sequence++; + ann.m_priority = m_tracker.ComputePriority(TXHASHES[txhash], peer, ann.m_preferred); + + // Add event so that AdvanceToEvent can quickly jump to the point where its reqtime passes. + if (reqtime > m_now) m_events.push(reqtime); + } + + // Call TxRequestTracker's implementation. + m_tracker.ReceivedInv(peer, GenTxid{is_wtxid, TXHASHES[txhash]}, preferred, reqtime); + } + + void RequestedTx(int peer, int txhash, std::chrono::microseconds exptime) + { + // Apply to naive structure: if a CANDIDATE announcement exists for peer/txhash, + // convert it to REQUESTED, and change any existing REQUESTED announcement for the same txhash to COMPLETED. + if (m_announcements[txhash][peer].m_state == State::CANDIDATE) { + for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) { + if (m_announcements[txhash][peer2].m_state == State::REQUESTED) { + m_announcements[txhash][peer2].m_state = State::COMPLETED; + } + } + m_announcements[txhash][peer].m_state = State::REQUESTED; + m_announcements[txhash][peer].m_time = exptime; + } + + // Add event so that AdvanceToEvent can quickly jump to the point where its exptime passes. + if (exptime > m_now) m_events.push(exptime); + + // Call TxRequestTracker's implementation. + m_tracker.RequestedTx(peer, TXHASHES[txhash], exptime); + } + + void ReceivedResponse(int peer, int txhash) + { + // Apply to naive structure: convert anything to COMPLETED. + if (m_announcements[txhash][peer].m_state != State::NOTHING) { + m_announcements[txhash][peer].m_state = State::COMPLETED; + Cleanup(txhash); + } + + // Call TxRequestTracker's implementation. + m_tracker.ReceivedResponse(peer, TXHASHES[txhash]); + } + + void GetRequestable(int peer) + { + // Implement using naive structure: + + //! list of (sequence number, txhash, is_wtxid) tuples. + std::vector<std::tuple<uint64_t, int, bool>> result; + std::vector<std::pair<NodeId, GenTxid>> expected_expired; + for (int txhash = 0; txhash < MAX_TXHASHES; ++txhash) { + // Mark any expired REQUESTED announcements as COMPLETED. + for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) { + Announcement& ann2 = m_announcements[txhash][peer2]; + if (ann2.m_state == State::REQUESTED && ann2.m_time <= m_now) { + expected_expired.emplace_back(peer2, GenTxid{ann2.m_is_wtxid, TXHASHES[txhash]}); + ann2.m_state = State::COMPLETED; + break; + } + } + // And delete txids with only COMPLETED announcements left. + Cleanup(txhash); + // CANDIDATEs for which this announcement has the highest priority get returned. + const Announcement& ann = m_announcements[txhash][peer]; + if (ann.m_state == State::CANDIDATE && GetSelected(txhash) == peer) { + result.emplace_back(ann.m_sequence, txhash, ann.m_is_wtxid); + } + } + // Sort the results by sequence number. + std::sort(result.begin(), result.end()); + std::sort(expected_expired.begin(), expected_expired.end()); + + // Compare with TxRequestTracker's implementation. + std::vector<std::pair<NodeId, GenTxid>> expired; + const auto actual = m_tracker.GetRequestable(peer, m_now, &expired); + std::sort(expired.begin(), expired.end()); + assert(expired == expected_expired); + + m_tracker.PostGetRequestableSanityCheck(m_now); + assert(result.size() == actual.size()); + for (size_t pos = 0; pos < actual.size(); ++pos) { + assert(TXHASHES[std::get<1>(result[pos])] == actual[pos].GetHash()); + assert(std::get<2>(result[pos]) == actual[pos].IsWtxid()); + } + } + + void Check() + { + // Compare CountTracked and CountLoad with naive structure. + size_t total = 0; + for (int peer = 0; peer < MAX_PEERS; ++peer) { + size_t tracked = 0; + size_t inflight = 0; + size_t candidates = 0; + for (int txhash = 0; txhash < MAX_TXHASHES; ++txhash) { + tracked += m_announcements[txhash][peer].m_state != State::NOTHING; + inflight += m_announcements[txhash][peer].m_state == State::REQUESTED; + candidates += m_announcements[txhash][peer].m_state == State::CANDIDATE; + } + assert(m_tracker.Count(peer) == tracked); + assert(m_tracker.CountInFlight(peer) == inflight); + assert(m_tracker.CountCandidates(peer) == candidates); + total += tracked; + } + // Compare Size. + assert(m_tracker.Size() == total); + + // Invoke internal consistency check of TxRequestTracker object. + m_tracker.SanityCheck(); + } +}; +} // namespace + +FUZZ_TARGET(txrequest) +{ + // Tester object (which encapsulates a TxRequestTracker). + Tester tester; + + // Decode the input as a sequence of instructions with parameters + auto it = buffer.begin(); + while (it != buffer.end()) { + int cmd = *(it++) % 11; + int peer, txidnum, delaynum; + switch (cmd) { + case 0: // Make time jump to the next event (m_time of CANDIDATE or REQUESTED) + tester.AdvanceToEvent(); + break; + case 1: // Change time + delaynum = it == buffer.end() ? 0 : *(it++); + tester.AdvanceTime(DELAYS[delaynum]); + break; + case 2: // Query for requestable txs + peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; + tester.GetRequestable(peer); + break; + case 3: // Peer went offline + peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; + tester.DisconnectedPeer(peer); + break; + case 4: // No longer need tx + txidnum = it == buffer.end() ? 0 : *(it++); + tester.ForgetTxHash(txidnum % MAX_TXHASHES); + break; + case 5: // Received immediate preferred inv + case 6: // Same, but non-preferred. + peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; + txidnum = it == buffer.end() ? 0 : *(it++); + tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, (txidnum / MAX_TXHASHES) & 1, cmd & 1, + std::chrono::microseconds::min()); + break; + case 7: // Received delayed preferred inv + case 8: // Same, but non-preferred. + peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; + txidnum = it == buffer.end() ? 0 : *(it++); + delaynum = it == buffer.end() ? 0 : *(it++); + tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, (txidnum / MAX_TXHASHES) & 1, cmd & 1, + tester.Now() + DELAYS[delaynum]); + break; + case 9: // Requested tx from peer + peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; + txidnum = it == buffer.end() ? 0 : *(it++); + delaynum = it == buffer.end() ? 0 : *(it++); + tester.RequestedTx(peer, txidnum % MAX_TXHASHES, tester.Now() + DELAYS[delaynum]); + break; + case 10: // Received response + peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS; + txidnum = it == buffer.end() ? 0 : *(it++); + tester.ReceivedResponse(peer, txidnum % MAX_TXHASHES); + break; + default: + assert(false); + } + } + tester.Check(); +} diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp new file mode 100644 index 0000000000..0a541e4186 --- /dev/null +++ b/src/test/fuzz/util.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <test/fuzz/util.h> +#include <version.h> + +void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept +{ + const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS); + const NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS); + const int32_t version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()); + const bool filter_txs = fuzzed_data_provider.ConsumeBool(); + + node.nServices = remote_services; + node.m_permissionFlags = permission_flags; + if (init_version) { + node.nVersion = version; + node.SetCommonVersion(std::min(version, PROTOCOL_VERSION)); + } + if (node.m_tx_relay != nullptr) { + LOCK(node.m_tx_relay->cs_filter); + node.m_tx_relay->fRelayTxes = filter_txs; + } +} diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index ed6093a8a8..e48771efa2 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -11,6 +11,8 @@ #include <chainparamsbase.h> #include <coins.h> #include <consensus/consensus.h> +#include <merkleblock.h> +#include <net.h> #include <netaddress.h> #include <netbase.h> #include <primitives/transaction.h> @@ -20,9 +22,12 @@ #include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> +#include <test/util/net.h> #include <test/util/setup_common.h> #include <txmempool.h> #include <uint256.h> +#include <util/time.h> +#include <util/vector.h> #include <version.h> #include <algorithm> @@ -32,18 +37,34 @@ #include <string> #include <vector> -NODISCARD inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +template <typename... Callables> +void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables) +{ + constexpr size_t call_size{sizeof...(callables)}; + static_assert(call_size >= 1); + const size_t call_index{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, call_size - 1)}; + + size_t i{0}; + return ((i++ == call_index ? callables() : void()), ...); +} + +[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept { const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length); return {s.begin(), s.end()}; } -NODISCARD inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +{ + return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length)); +} + +[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept { return {ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION}; } -NODISCARD inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept +[[nodiscard]] inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept { const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size); std::vector<std::string> r; @@ -54,7 +75,7 @@ NODISCARD inline std::vector<std::string> ConsumeRandomLengthStringVector(Fuzzed } template <typename T> -NODISCARD inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept +[[nodiscard]] inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept { const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size); std::vector<T> r; @@ -65,7 +86,7 @@ NODISCARD inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProv } template <typename T> -NODISCARD inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept { const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION}; @@ -78,28 +99,44 @@ NODISCARD inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzz return obj; } -NODISCARD inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept +template <typename WeakEnumType, size_t size> +[[nodiscard]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept +{ + return fuzzed_data_provider.ConsumeBool() ? + fuzzed_data_provider.PickValueInArray<WeakEnumType>(all_types) : + WeakEnumType(fuzzed_data_provider.ConsumeIntegral<typename std::underlying_type<WeakEnumType>::type>()); +} + +[[nodiscard]] inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept { return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE)); } -NODISCARD inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept { return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY); } -NODISCARD inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + // Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) is a no-op. + static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z"); + static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z"); + return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max); +} + +[[nodiscard]] inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept { const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); return {b.begin(), b.end()}; } -NODISCARD inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept { return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()}; } -NODISCARD inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider) noexcept { const std::vector<uint8_t> v160 = fuzzed_data_provider.ConsumeBytes<uint8_t>(160 / 8); if (v160.size() != 160 / 8) { @@ -108,7 +145,7 @@ NODISCARD inline uint160 ConsumeUInt160(FuzzedDataProvider& fuzzed_data_provider return uint160{v160}; } -NODISCARD inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept { const std::vector<uint8_t> v256 = fuzzed_data_provider.ConsumeBytes<uint8_t>(256 / 8); if (v256.size() != 256 / 8) { @@ -117,12 +154,12 @@ NODISCARD inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider return uint256{v256}; } -NODISCARD inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept { return UintToArith256(ConsumeUInt256(fuzzed_data_provider)); } -NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept +[[nodiscard]] inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept { // Avoid: // policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long' @@ -137,45 +174,39 @@ NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzze return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}}; } -NODISCARD inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept { CTxDestination tx_destination; - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) { - case 0: { - tx_destination = CNoDestination{}; - break; - } - case 1: { - tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)}; - break; - } - case 2: { - tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)}; - break; - } - case 3: { - tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)}; - break; - } - case 4: { - tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)}; - break; - } - case 5: { - WitnessUnknown witness_unknown{}; - witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<int>(); - const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40); - witness_unknown.length = witness_unknown_program_1.size(); - std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program); - tx_destination = witness_unknown; - break; - } - } + CallOneOf( + fuzzed_data_provider, + [&] { + tx_destination = CNoDestination{}; + }, + [&] { + tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)}; + }, + [&] { + tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)}; + }, + [&] { + tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)}; + }, + [&] { + tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)}; + }, + [&] { + WitnessUnknown witness_unknown{}; + witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); + const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40); + witness_unknown.length = witness_unknown_program_1.size(); + std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program); + tx_destination = witness_unknown; + }); return tx_destination; } template <typename T> -NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept +[[nodiscard]] bool MultiplicationOverflow(const T i, const T j) noexcept { static_assert(std::is_integral<T>::value, "Integral required."); if (std::numeric_limits<T>::is_signed) { @@ -198,7 +229,7 @@ NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept } template <class T> -NODISCARD bool AdditionOverflow(const T i, const T j) noexcept +[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept { static_assert(std::is_integral<T>::value, "Integral required."); if (std::numeric_limits<T>::is_signed) { @@ -208,7 +239,7 @@ NODISCARD bool AdditionOverflow(const T i, const T j) noexcept return std::numeric_limits<T>::max() - i < j; } -NODISCARD inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept +[[nodiscard]] inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept { for (const CTxIn& tx_in : tx.vin) { const Coin& coin = inputs.AccessCoin(tx_in.prevout); @@ -223,7 +254,7 @@ NODISCARD inline bool ContainsSpentInput(const CTransaction& tx, const CCoinsVie * Returns a byte vector of specified size regardless of the number of remaining bytes available * from the fuzzer. Pads with zero value bytes if needed to achieve the specified size. */ -NODISCARD inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t length) noexcept +[[nodiscard]] inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t length) noexcept { std::vector<uint8_t> result(length); const std::vector<uint8_t> random_bytes = fuzzed_data_provider.ConsumeBytes<uint8_t>(length); @@ -233,13 +264,13 @@ NODISCARD inline std::vector<uint8_t> ConsumeFixedLengthByteVector(FuzzedDataPro return result; } -CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept +inline CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept { const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION}); CNetAddr net_addr; if (network == Network::NET_IPV4) { - const in_addr v4_addr = { - .s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; + in_addr v4_addr = {}; + v4_addr.s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); net_addr = CNetAddr{v4_addr}; } else if (network == Network::NET_IPV6) { if (fuzzed_data_provider.remaining_bytes() >= 16) { @@ -255,14 +286,55 @@ CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept return net_addr; } -CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept +inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept { return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()}; } -void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST) +inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()}; +} + +inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept { - static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}}; + return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; +} + +template <bool ReturnUniquePtr = false> +auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept +{ + const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegral<NodeId>()); + const ServiceFlags local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS); + const SOCKET socket = INVALID_SOCKET; + const CAddress address = ConsumeAddress(fuzzed_data_provider); + const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); + const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); + const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider); + const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64); + const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES); + const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false}; + if constexpr (ReturnUniquePtr) { + return std::make_unique<CNode>(node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion); + } else { + return CNode{node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion}; + } +} +inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); } + +void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept; + +template <class T = const BasicTestingSetup> +std::unique_ptr<T> MakeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST, const std::vector<const char*>& extra_args = {}) +{ + // Prepend default arguments for fuzzing + const std::vector<const char*> arguments = Cat( + { + "-nodebuglogfile", + }, + extra_args); + + return MakeUnique<T>(chain_name, arguments); } class FuzzedFileProvider @@ -281,32 +353,26 @@ public: return nullptr; } std::string mode; - switch (m_fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) { - case 0: { - mode = "r"; - break; - } - case 1: { - mode = "r+"; - break; - } - case 2: { - mode = "w"; - break; - } - case 3: { - mode = "w+"; - break; - } - case 4: { - mode = "a"; - break; - } - case 5: { - mode = "a+"; - break; - } - } + CallOneOf( + m_fuzzed_data_provider, + [&] { + mode = "r"; + }, + [&] { + mode = "r+"; + }, + [&] { + mode = "w"; + }, + [&] { + mode = "w+"; + }, + [&] { + mode = "a"; + }, + [&] { + mode = "a+"; + }); #ifdef _GNU_SOURCE const cookie_io_functions_t io_hooks = { FuzzedFileProvider::read, @@ -378,7 +444,7 @@ public: } }; -NODISCARD inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline FuzzedFileProvider ConsumeFile(FuzzedDataProvider& fuzzed_data_provider) noexcept { return {fuzzed_data_provider}; } @@ -399,71 +465,69 @@ public: } }; -NODISCARD inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept +[[nodiscard]] inline FuzzedAutoFileProvider ConsumeAutoFile(FuzzedDataProvider& fuzzed_data_provider) noexcept { return {fuzzed_data_provider}; } -#define WRITE_TO_STREAM_CASE(id, type, consume) \ - case id: { \ - type o = consume; \ - stream << o; \ - break; \ +#define WRITE_TO_STREAM_CASE(type, consume) \ + [&] { \ + type o = consume; \ + stream << o; \ } template <typename Stream> void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept { while (fuzzed_data_provider.ConsumeBool()) { try { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) { - WRITE_TO_STREAM_CASE(0, bool, fuzzed_data_provider.ConsumeBool()) - WRITE_TO_STREAM_CASE(1, char, fuzzed_data_provider.ConsumeIntegral<char>()) - WRITE_TO_STREAM_CASE(2, int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()) - WRITE_TO_STREAM_CASE(3, uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()) - WRITE_TO_STREAM_CASE(4, int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()) - WRITE_TO_STREAM_CASE(5, uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>()) - WRITE_TO_STREAM_CASE(6, int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()) - WRITE_TO_STREAM_CASE(7, uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>()) - WRITE_TO_STREAM_CASE(8, int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()) - WRITE_TO_STREAM_CASE(9, uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()) - WRITE_TO_STREAM_CASE(10, float, fuzzed_data_provider.ConsumeFloatingPoint<float>()) - WRITE_TO_STREAM_CASE(11, double, fuzzed_data_provider.ConsumeFloatingPoint<double>()) - WRITE_TO_STREAM_CASE(12, std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)) - WRITE_TO_STREAM_CASE(13, std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider)) - } + CallOneOf( + fuzzed_data_provider, + WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()), + WRITE_TO_STREAM_CASE(char, fuzzed_data_provider.ConsumeIntegral<char>()), + WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()), + WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()), + WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()), + WRITE_TO_STREAM_CASE(uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>()), + WRITE_TO_STREAM_CASE(int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()), + WRITE_TO_STREAM_CASE(uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>()), + WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()), + WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()), + WRITE_TO_STREAM_CASE(float, fuzzed_data_provider.ConsumeFloatingPoint<float>()), + WRITE_TO_STREAM_CASE(double, fuzzed_data_provider.ConsumeFloatingPoint<double>()), + WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)), + WRITE_TO_STREAM_CASE(std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider))); } catch (const std::ios_base::failure&) { break; } } } -#define READ_FROM_STREAM_CASE(id, type) \ - case id: { \ - type o; \ - stream >> o; \ - break; \ +#define READ_FROM_STREAM_CASE(type) \ + [&] { \ + type o; \ + stream >> o; \ } template <typename Stream> void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept { while (fuzzed_data_provider.ConsumeBool()) { try { - switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) { - READ_FROM_STREAM_CASE(0, bool) - READ_FROM_STREAM_CASE(1, char) - READ_FROM_STREAM_CASE(2, int8_t) - READ_FROM_STREAM_CASE(3, uint8_t) - READ_FROM_STREAM_CASE(4, int16_t) - READ_FROM_STREAM_CASE(5, uint16_t) - READ_FROM_STREAM_CASE(6, int32_t) - READ_FROM_STREAM_CASE(7, uint32_t) - READ_FROM_STREAM_CASE(8, int64_t) - READ_FROM_STREAM_CASE(9, uint64_t) - READ_FROM_STREAM_CASE(10, float) - READ_FROM_STREAM_CASE(11, double) - READ_FROM_STREAM_CASE(12, std::string) - READ_FROM_STREAM_CASE(13, std::vector<char>) - } + CallOneOf( + fuzzed_data_provider, + READ_FROM_STREAM_CASE(bool), + READ_FROM_STREAM_CASE(char), + READ_FROM_STREAM_CASE(int8_t), + READ_FROM_STREAM_CASE(uint8_t), + READ_FROM_STREAM_CASE(int16_t), + READ_FROM_STREAM_CASE(uint16_t), + READ_FROM_STREAM_CASE(int32_t), + READ_FROM_STREAM_CASE(uint32_t), + READ_FROM_STREAM_CASE(int64_t), + READ_FROM_STREAM_CASE(uint64_t), + READ_FROM_STREAM_CASE(float), + READ_FROM_STREAM_CASE(double), + READ_FROM_STREAM_CASE(std::string), + READ_FROM_STREAM_CASE(std::vector<char>)); } catch (const std::ios_base::failure&) { break; } diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp index b0d4de89f3..73463b071e 100644 --- a/src/test/interfaces_tests.cpp +++ b/src/test/interfaces_tests.cpp @@ -17,8 +17,8 @@ BOOST_FIXTURE_TEST_SUITE(interfaces_tests, TestChain100Setup) BOOST_AUTO_TEST_CASE(findBlock) { - auto chain = interfaces::MakeChain(m_node); - auto& active = ChainActive(); + auto& chain = m_node.chain; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); uint256 hash; BOOST_CHECK(chain->findBlock(active[10]->GetBlockHash(), FoundBlock().hash(hash))); @@ -44,13 +44,25 @@ BOOST_AUTO_TEST_CASE(findBlock) BOOST_CHECK(chain->findBlock(active[60]->GetBlockHash(), FoundBlock().mtpTime(mtp_time))); BOOST_CHECK_EQUAL(mtp_time, active[60]->GetMedianTimePast()); + bool cur_active{false}, next_active{false}; + uint256 next_hash; + BOOST_CHECK_EQUAL(active.Height(), 100); + BOOST_CHECK(chain->findBlock(active[99]->GetBlockHash(), FoundBlock().inActiveChain(cur_active).nextBlock(FoundBlock().inActiveChain(next_active).hash(next_hash)))); + BOOST_CHECK(cur_active); + BOOST_CHECK(next_active); + BOOST_CHECK_EQUAL(next_hash, active[100]->GetBlockHash()); + cur_active = next_active = false; + BOOST_CHECK(chain->findBlock(active[100]->GetBlockHash(), FoundBlock().inActiveChain(cur_active).nextBlock(FoundBlock().inActiveChain(next_active)))); + BOOST_CHECK(cur_active); + BOOST_CHECK(!next_active); + BOOST_CHECK(!chain->findBlock({}, FoundBlock())); } BOOST_AUTO_TEST_CASE(findFirstBlockWithTimeAndHeight) { - auto chain = interfaces::MakeChain(m_node); - auto& active = ChainActive(); + auto& chain = m_node.chain; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); uint256 hash; int height; BOOST_CHECK(chain->findFirstBlockWithTimeAndHeight(/* min_time= */ 0, /* min_height= */ 5, FoundBlock().hash(hash).height(height))); @@ -59,25 +71,10 @@ BOOST_AUTO_TEST_CASE(findFirstBlockWithTimeAndHeight) BOOST_CHECK(!chain->findFirstBlockWithTimeAndHeight(/* min_time= */ active.Tip()->GetBlockTimeMax() + 1, /* min_height= */ 0)); } -BOOST_AUTO_TEST_CASE(findNextBlock) -{ - auto chain = interfaces::MakeChain(m_node); - auto& active = ChainActive(); - bool reorg; - uint256 hash; - BOOST_CHECK(chain->findNextBlock(active[20]->GetBlockHash(), 20, FoundBlock().hash(hash), &reorg)); - BOOST_CHECK_EQUAL(hash, active[21]->GetBlockHash()); - BOOST_CHECK_EQUAL(reorg, false); - BOOST_CHECK(!chain->findNextBlock(uint256(), 20, {}, &reorg)); - BOOST_CHECK_EQUAL(reorg, true); - BOOST_CHECK(!chain->findNextBlock(active.Tip()->GetBlockHash(), active.Height(), {}, &reorg)); - BOOST_CHECK_EQUAL(reorg, false); -} - BOOST_AUTO_TEST_CASE(findAncestorByHeight) { - auto chain = interfaces::MakeChain(m_node); - auto& active = ChainActive(); + auto& chain = m_node.chain; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); uint256 hash; BOOST_CHECK(chain->findAncestorByHeight(active[20]->GetBlockHash(), 10, FoundBlock().hash(hash))); BOOST_CHECK_EQUAL(hash, active[10]->GetBlockHash()); @@ -86,8 +83,8 @@ BOOST_AUTO_TEST_CASE(findAncestorByHeight) BOOST_AUTO_TEST_CASE(findAncestorByHash) { - auto chain = interfaces::MakeChain(m_node); - auto& active = ChainActive(); + auto& chain = m_node.chain; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); int height = -1; BOOST_CHECK(chain->findAncestorByHash(active[20]->GetBlockHash(), active[10]->GetBlockHash(), FoundBlock().height(height))); BOOST_CHECK_EQUAL(height, 10); @@ -96,8 +93,8 @@ BOOST_AUTO_TEST_CASE(findAncestorByHash) BOOST_AUTO_TEST_CASE(findCommonAncestor) { - auto chain = interfaces::MakeChain(m_node); - auto& active = ChainActive(); + auto& chain = m_node.chain; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); auto* orig_tip = active.Tip(); for (int i = 0; i < 10; ++i) { BlockValidationState state; @@ -126,8 +123,8 @@ BOOST_AUTO_TEST_CASE(findCommonAncestor) BOOST_AUTO_TEST_CASE(hasBlocks) { - auto chain = interfaces::MakeChain(m_node); - auto& active = ChainActive(); + auto& chain = m_node.chain; + const CChain& active = Assert(m_node.chainman)->ActiveChain(); // Test ranges BOOST_CHECK(chain->hasBlocks(active.Tip()->GetBlockHash(), 10, 90)); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 4e4c44266a..cb66d5164e 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -172,20 +172,30 @@ BOOST_AUTO_TEST_CASE(key_signature_tests) } BOOST_CHECK(found); - // When entropy is not specified, we should always see low R signatures that are less than 70 bytes in 256 tries + // When entropy is not specified, we should always see low R signatures that are less than or equal to 70 bytes in 256 tries + // The low R signatures should always have the value of their "length of R" byte less than or equal to 32 // We should see at least one signature that is less than 70 bytes. - found = true; bool found_small = false; + bool found_big = false; + bool bad_sign = false; for (int i = 0; i < 256; ++i) { sig.clear(); std::string msg = "A message to be signed" + ToString(i); msg_hash = Hash(msg); - BOOST_CHECK(key.Sign(msg_hash, sig)); - found = sig[3] == 0x20; - BOOST_CHECK(sig.size() <= 70); + if (!key.Sign(msg_hash, sig)) { + bad_sign = true; + break; + } + // sig.size() > 70 implies sig[3] > 32, because S is always low. + // But check both conditions anyway, just in case this implication is broken for some reason + if (sig[3] > 32 || sig.size() > 70) { + found_big = true; + break; + } found_small |= sig.size() < 70; } - BOOST_CHECK(found); + BOOST_CHECK(!bad_sign); + BOOST_CHECK(!found_big); BOOST_CHECK(found_small); } @@ -264,4 +274,32 @@ BOOST_AUTO_TEST_CASE(pubkey_unserialize) } } +BOOST_AUTO_TEST_CASE(bip340_test_vectors) +{ + static const std::vector<std::pair<std::array<std::string, 3>, bool>> VECTORS = { + {{"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9", "0000000000000000000000000000000000000000000000000000000000000000", "E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0"}, true}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A"}, true}, + {{"DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8", "7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C", "5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7"}, true}, + {{"25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3"}, true}, + {{"D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9", "4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703", "00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4"}, true}, + {{"EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false}, + {{"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"}, false}, + {{"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30", "243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89", "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B"}, false} + }; + + for (const auto& test : VECTORS) { + auto pubkey = ParseHex(test.first[0]); + auto msg = ParseHex(test.first[1]); + auto sig = ParseHex(test.first[2]); + BOOST_CHECK_EQUAL(XOnlyPubKey(pubkey).VerifySchnorr(uint256(msg), sig), test.second); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp deleted file mode 100644 index ea18debbd3..0000000000 --- a/src/test/limitedmap_tests.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// 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. - -#include <limitedmap.h> - -#include <test/util/setup_common.h> - -#include <boost/test/unit_test.hpp> - -BOOST_FIXTURE_TEST_SUITE(limitedmap_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(limitedmap_test) -{ - // create a limitedmap capped at 10 items - limitedmap<int, int> map(10); - - // check that the max size is 10 - BOOST_CHECK(map.max_size() == 10); - - // check that it's empty - BOOST_CHECK(map.size() == 0); - - // insert (-1, -1) - map.insert(std::pair<int, int>(-1, -1)); - - // make sure that the size is updated - BOOST_CHECK(map.size() == 1); - - // make sure that the new item is in the map - BOOST_CHECK(map.count(-1) == 1); - - // insert 10 new items - for (int i = 0; i < 10; i++) { - map.insert(std::pair<int, int>(i, i + 1)); - } - - // make sure that the map now contains 10 items... - BOOST_CHECK(map.size() == 10); - - // ...and that the first item has been discarded - BOOST_CHECK(map.count(-1) == 0); - - // iterate over the map, both with an index and an iterator - limitedmap<int, int>::const_iterator it = map.begin(); - for (int i = 0; i < 10; i++) { - // make sure the item is present - BOOST_CHECK(map.count(i) == 1); - - // use the iterator to check for the expected key and value - BOOST_CHECK(it->first == i); - BOOST_CHECK(it->second == i + 1); - - // use find to check for the value - BOOST_CHECK(map.find(i)->second == i + 1); - - // update and recheck - map.update(it, i + 2); - BOOST_CHECK(map.find(i)->second == i + 2); - - it++; - } - - // check that we've exhausted the iterator - BOOST_CHECK(it == map.end()); - - // resize the map to 5 items - map.max_size(5); - - // check that the max size and size are now 5 - BOOST_CHECK(map.max_size() == 5); - BOOST_CHECK(map.size() == 5); - - // check that items less than 5 have been discarded - // and items greater than 5 are retained - for (int i = 0; i < 10; i++) { - if (i < 5) { - BOOST_CHECK(map.count(i) == 0); - } else { - BOOST_CHECK(map.count(i) == 1); - } - } - - // erase some items not in the map - for (int i = 100; i < 1000; i += 100) { - map.erase(i); - } - - // check that the size is unaffected - BOOST_CHECK(map.size() == 5); - - // erase the remaining elements - for (int i = 5; i < 10; i++) { - map.erase(i); - } - - // check that the map is now empty - BOOST_CHECK(map.empty()); -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 9bc7cc5dab..942d54ede8 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 8686012af7..e967273636 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -198,7 +198,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { // Note that by default, these tests run with size accounting enabled. - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); const CChainParams& chainparams = *chainParams; CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; std::unique_ptr<CBlockTemplate> pblocktemplate; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 261396cd0c..a1b41e17ed 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -9,6 +9,7 @@ #include <cstdint> #include <net.h> #include <netbase.h> +#include <optional.h> #include <serialize.h> #include <span.h> #include <streams.h> @@ -21,10 +22,13 @@ #include <boost/test/unit_test.hpp> +#include <algorithm> #include <ios> #include <memory> #include <string> +using namespace std::literals; + class CAddrManSerializationMock : public CAddrMan { public: @@ -73,7 +77,7 @@ public: } }; -static CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman) +static CDataStream AddrmanToStream(const CAddrManSerializationMock& _addrman) { CDataStream ssPeersIn(SER_DISK, CLIENT_VERSION); ssPeersIn << Params().MessageStart(); @@ -106,8 +110,8 @@ BOOST_AUTO_TEST_CASE(caddrdb_read) BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false)); BOOST_CHECK(Lookup("250.7.2.2", addr2, 9999, false)); BOOST_CHECK(Lookup("250.7.3.3", addr3, 9999, false)); - BOOST_CHECK(Lookup(std::string("250.7.3.3", 9), addr3, 9999, false)); - BOOST_CHECK(!Lookup(std::string("250.7.3.3\0example.com", 21), addr3, 9999, false)); + BOOST_CHECK(Lookup("250.7.3.3"s, addr3, 9999, false)); + BOOST_CHECK(!Lookup("250.7.3.3\0example.com"s, addr3, 9999, false)); // Add three addresses to new table. CService source; @@ -177,7 +181,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) { SOCKET hSocket = INVALID_SOCKET; NodeId id = 0; - int height = 0; in_addr ipv4Addr; ipv4Addr.s_addr = 0xa0b0c001; @@ -185,21 +188,64 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK); std::string pszDest; - std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY); + std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>( + id++, NODE_NETWORK, hSocket, addr, + /* nKeyedNetGroupIn = */ 0, + /* nLocalHostNonceIn = */ 0, + CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY); BOOST_CHECK(pnode1->IsFullOutboundConn() == true); BOOST_CHECK(pnode1->IsManualConn() == false); BOOST_CHECK(pnode1->IsBlockOnlyConn() == false); BOOST_CHECK(pnode1->IsFeelerConn() == false); BOOST_CHECK(pnode1->IsAddrFetchConn() == false); BOOST_CHECK(pnode1->IsInboundConn() == false); - - std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, ConnectionType::INBOUND); + BOOST_CHECK(pnode1->IsInboundOnion() == false); + BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4); + + std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>( + id++, NODE_NETWORK, hSocket, addr, + /* nKeyedNetGroupIn = */ 1, + /* nLocalHostNonceIn = */ 1, + CAddress(), pszDest, ConnectionType::INBOUND, + /* inbound_onion = */ false); BOOST_CHECK(pnode2->IsFullOutboundConn() == false); BOOST_CHECK(pnode2->IsManualConn() == false); BOOST_CHECK(pnode2->IsBlockOnlyConn() == false); BOOST_CHECK(pnode2->IsFeelerConn() == false); BOOST_CHECK(pnode2->IsAddrFetchConn() == false); BOOST_CHECK(pnode2->IsInboundConn() == true); + BOOST_CHECK(pnode2->IsInboundOnion() == false); + BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4); + + std::unique_ptr<CNode> pnode3 = MakeUnique<CNode>( + id++, NODE_NETWORK, hSocket, addr, + /* nKeyedNetGroupIn = */ 0, + /* nLocalHostNonceIn = */ 0, + CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY, + /* inbound_onion = */ false); + BOOST_CHECK(pnode3->IsFullOutboundConn() == true); + BOOST_CHECK(pnode3->IsManualConn() == false); + BOOST_CHECK(pnode3->IsBlockOnlyConn() == false); + BOOST_CHECK(pnode3->IsFeelerConn() == false); + BOOST_CHECK(pnode3->IsAddrFetchConn() == false); + BOOST_CHECK(pnode3->IsInboundConn() == false); + BOOST_CHECK(pnode3->IsInboundOnion() == false); + BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4); + + std::unique_ptr<CNode> pnode4 = MakeUnique<CNode>( + id++, NODE_NETWORK, hSocket, addr, + /* nKeyedNetGroupIn = */ 1, + /* nLocalHostNonceIn = */ 1, + CAddress(), pszDest, ConnectionType::INBOUND, + /* inbound_onion = */ true); + BOOST_CHECK(pnode4->IsFullOutboundConn() == false); + BOOST_CHECK(pnode4->IsManualConn() == false); + BOOST_CHECK(pnode4->IsBlockOnlyConn() == false); + BOOST_CHECK(pnode4->IsFeelerConn() == false); + BOOST_CHECK(pnode4->IsAddrFetchConn() == false); + BOOST_CHECK(pnode4->IsInboundConn() == true); + BOOST_CHECK(pnode4->IsInboundOnion() == true); + BOOST_CHECK_EQUAL(pnode4->ConnectedThroughNetwork(), Network::NET_ONION); } BOOST_AUTO_TEST_CASE(cnetaddr_basic) @@ -212,6 +258,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsIPv4()); BOOST_CHECK(addr.IsBindAny()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "0.0.0.0"); // IPv4, INADDR_NONE @@ -220,6 +267,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsIPv4()); BOOST_CHECK(!addr.IsBindAny()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "255.255.255.255"); // IPv4, casual @@ -228,6 +276,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsIPv4()); BOOST_CHECK(!addr.IsBindAny()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "12.34.56.78"); // IPv6, in6addr_any @@ -236,6 +285,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsIPv6()); BOOST_CHECK(addr.IsBindAny()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "::"); // IPv6, casual @@ -244,14 +294,35 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsIPv6()); BOOST_CHECK(!addr.IsBindAny()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "1122:3344:5566:7788:9900:aabb:ccdd:eeff"); + // IPv6, scoped/link-local. See https://tools.ietf.org/html/rfc4007 + // We support non-negative decimal integers (uint32_t) as zone id indices. + // Test with a fairly-high value, e.g. 32, to avoid locally reserved ids. + const std::string link_local{"fe80::1"}; + const std::string scoped_addr{link_local + "%32"}; + BOOST_REQUIRE(LookupHost(scoped_addr, addr, false)); + BOOST_REQUIRE(addr.IsValid()); + BOOST_REQUIRE(addr.IsIPv6()); + BOOST_CHECK(!addr.IsBindAny()); + const std::string addr_str{addr.ToString()}; + BOOST_CHECK(addr_str == scoped_addr || addr_str == "fe80:0:0:0:0:0:0:1"); + // The fallback case "fe80:0:0:0:0:0:0:1" is needed for macOS 10.14/10.15 and (probably) later. + // Test that the delimiter "%" and default zone id of 0 can be omitted for the default scope. + BOOST_REQUIRE(LookupHost(link_local + "%0", addr, false)); + BOOST_REQUIRE(addr.IsValid()); + BOOST_REQUIRE(addr.IsIPv6()); + BOOST_CHECK(!addr.IsBindAny()); + BOOST_CHECK_EQUAL(addr.ToString(), link_local); + // TORv2 BOOST_REQUIRE(addr.SetSpecial("6hzph5hv6337r6p2.onion")); BOOST_REQUIRE(addr.IsValid()); BOOST_REQUIRE(addr.IsTor()); BOOST_CHECK(!addr.IsBindAny()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion"); // TORv3 @@ -261,6 +332,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsTor()); BOOST_CHECK(!addr.IsBindAny()); + BOOST_CHECK(!addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), torv3_addr); // TORv3, broken, with wrong checksum @@ -285,6 +357,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_basic) BOOST_REQUIRE(addr.IsInternal()); BOOST_CHECK(!addr.IsBindAny()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "esffpvrt3wpeaygy.internal"); // Totally bogus @@ -379,6 +452,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) s >> addr; BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsIPv4()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "1.2.3.4"); BOOST_REQUIRE(s.empty()); @@ -415,6 +489,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) s >> addr; BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsIPv6()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "102:304:506:708:90a:b0c:d0e:f10"); BOOST_REQUIRE(s.empty()); @@ -426,6 +501,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) // sha256(name)[0:10] s >> addr; BOOST_CHECK(addr.IsInternal()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "zklycewkdo64v6wc.internal"); BOOST_REQUIRE(s.empty()); @@ -461,6 +537,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) s >> addr; BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsTor()); + BOOST_CHECK(addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "6hzph5hv6337r6p2.onion"); BOOST_REQUIRE(s.empty()); @@ -482,6 +559,7 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) s >> addr; BOOST_CHECK(addr.IsValid()); BOOST_CHECK(addr.IsTor()); + BOOST_CHECK(!addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"); BOOST_REQUIRE(s.empty()); @@ -503,6 +581,8 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) "f98232ae42d4b6fd2fa81952dfe36a87")); s >> addr; BOOST_CHECK(addr.IsValid()); + BOOST_CHECK(addr.IsI2P()); + BOOST_CHECK(!addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p"); BOOST_REQUIRE(s.empty()); @@ -524,9 +604,21 @@ BOOST_AUTO_TEST_CASE(cnetaddr_unserialize_v2) )); s >> addr; BOOST_CHECK(addr.IsValid()); + BOOST_CHECK(addr.IsCJDNS()); + BOOST_CHECK(!addr.IsAddrV1Compatible()); BOOST_CHECK_EQUAL(addr.ToString(), "fc00:1:2:3:4:5:6:7"); BOOST_REQUIRE(s.empty()); + // Invalid CJDNS, wrong prefix. + s << MakeSpan(ParseHex("06" // network type (CJDNS) + "10" // address length + "aa000001000200030004000500060007" // address + )); + s >> addr; + BOOST_CHECK(addr.IsCJDNS()); + BOOST_CHECK(!addr.IsValid()); + BOOST_REQUIRE(s.empty()); + // Invalid CJDNS, with bogus length. s << MakeSpan(ParseHex("06" // network type (CJDNS) "01" // address length @@ -587,7 +679,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) in_addr ipv4AddrPeer; ipv4AddrPeer.s_addr = 0xa0b0c001; CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK); - std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY); + std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY); pnode->fSuccessfullyConnected.store(true); // the peer claims to be reaching us via IPv6 @@ -694,4 +786,147 @@ BOOST_AUTO_TEST_CASE(PoissonNextSend) g_mock_deterministic_tests = false; } +std::vector<NodeEvictionCandidate> GetRandomNodeEvictionCandidates(const int n_candidates, FastRandomContext& random_context) +{ + std::vector<NodeEvictionCandidate> candidates; + for (int id = 0; id < n_candidates; ++id) { + candidates.push_back({ + /* id */ id, + /* nTimeConnected */ static_cast<int64_t>(random_context.randrange(100)), + /* nMinPingUsecTime */ static_cast<int64_t>(random_context.randrange(100)), + /* nLastBlockTime */ static_cast<int64_t>(random_context.randrange(100)), + /* nLastTXTime */ static_cast<int64_t>(random_context.randrange(100)), + /* fRelevantServices */ random_context.randbool(), + /* fRelayTxes */ random_context.randbool(), + /* fBloomFilter */ random_context.randbool(), + /* nKeyedNetGroup */ random_context.randrange(100), + /* prefer_evict */ random_context.randbool(), + /* m_is_local */ random_context.randbool(), + }); + } + return candidates; +} + +// Returns true if any of the node ids in node_ids are selected for eviction. +bool IsEvicted(std::vector<NodeEvictionCandidate> candidates, const std::vector<NodeId>& node_ids, FastRandomContext& random_context) +{ + Shuffle(candidates.begin(), candidates.end(), random_context); + const Optional<NodeId> evicted_node_id = SelectNodeToEvict(std::move(candidates)); + if (!evicted_node_id) { + return false; + } + return std::find(node_ids.begin(), node_ids.end(), *evicted_node_id) != node_ids.end(); +} + +// Create number_of_nodes random nodes, apply setup function candidate_setup_fn, +// apply eviction logic and then return true if any of the node ids in node_ids +// are selected for eviction. +bool IsEvicted(const int number_of_nodes, std::function<void(NodeEvictionCandidate&)> candidate_setup_fn, const std::vector<NodeId>& node_ids, FastRandomContext& random_context) +{ + std::vector<NodeEvictionCandidate> candidates = GetRandomNodeEvictionCandidates(number_of_nodes, random_context); + for (NodeEvictionCandidate& candidate : candidates) { + candidate_setup_fn(candidate); + } + return IsEvicted(candidates, node_ids, random_context); +} + +namespace { +constexpr int NODE_EVICTION_TEST_ROUNDS{10}; +constexpr int NODE_EVICTION_TEST_UP_TO_N_NODES{200}; +} // namespace + +BOOST_AUTO_TEST_CASE(node_eviction_test) +{ + FastRandomContext random_context{true}; + + for (int i = 0; i < NODE_EVICTION_TEST_ROUNDS; ++i) { + for (int number_of_nodes = 0; number_of_nodes < NODE_EVICTION_TEST_UP_TO_N_NODES; ++number_of_nodes) { + // Four nodes with the highest keyed netgroup values should be + // protected from eviction. + BOOST_CHECK(!IsEvicted( + number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) { + candidate.nKeyedNetGroup = number_of_nodes - candidate.id; + }, + {0, 1, 2, 3}, random_context)); + + // Eight nodes with the lowest minimum ping time should be protected + // from eviction. + BOOST_CHECK(!IsEvicted( + number_of_nodes, [](NodeEvictionCandidate& candidate) { + candidate.nMinPingUsecTime = candidate.id; + }, + {0, 1, 2, 3, 4, 5, 6, 7}, random_context)); + + // Four nodes that most recently sent us novel transactions accepted + // into our mempool should be protected from eviction. + BOOST_CHECK(!IsEvicted( + number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) { + candidate.nLastTXTime = number_of_nodes - candidate.id; + }, + {0, 1, 2, 3}, random_context)); + + // Up to eight non-tx-relay peers that most recently sent us novel + // blocks should be protected from eviction. + BOOST_CHECK(!IsEvicted( + number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) { + candidate.nLastBlockTime = number_of_nodes - candidate.id; + if (candidate.id <= 7) { + candidate.fRelayTxes = false; + candidate.fRelevantServices = true; + } + }, + {0, 1, 2, 3, 4, 5, 6, 7}, random_context)); + + // Four peers that most recently sent us novel blocks should be + // protected from eviction. + BOOST_CHECK(!IsEvicted( + number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) { + candidate.nLastBlockTime = number_of_nodes - candidate.id; + }, + {0, 1, 2, 3}, random_context)); + + // Combination of the previous two tests. + BOOST_CHECK(!IsEvicted( + number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) { + candidate.nLastBlockTime = number_of_nodes - candidate.id; + if (candidate.id <= 7) { + candidate.fRelayTxes = false; + candidate.fRelevantServices = true; + } + }, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, random_context)); + + // Combination of all tests above. + BOOST_CHECK(!IsEvicted( + number_of_nodes, [number_of_nodes](NodeEvictionCandidate& candidate) { + candidate.nKeyedNetGroup = number_of_nodes - candidate.id; // 4 protected + candidate.nMinPingUsecTime = candidate.id; // 8 protected + candidate.nLastTXTime = number_of_nodes - candidate.id; // 4 protected + candidate.nLastBlockTime = number_of_nodes - candidate.id; // 4 protected + }, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, random_context)); + + // An eviction is expected given >= 29 random eviction candidates. The eviction logic protects at most + // four peers by net group, eight by lowest ping time, four by last time of novel tx, up to eight non-tx-relay + // peers by last novel block time, and four more peers by last novel block time. + if (number_of_nodes >= 29) { + BOOST_CHECK(SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context))); + } + + // No eviction is expected given <= 20 random eviction candidates. The eviction logic protects at least + // four peers by net group, eight by lowest ping time, four by last time of novel tx and four peers by last + // novel block time. + if (number_of_nodes <= 20) { + BOOST_CHECK(!SelectNodeToEvict(GetRandomNodeEvictionCandidates(number_of_nodes, random_context))); + } + + // Cases left to test: + // * "Protect the half of the remaining nodes which have been connected the longest. [...]" + // * "Pick out up to 1/4 peers that are localhost, sorted by longest uptime. [...]" + // * "If any remaining peers are preferred for eviction consider only them. [...]" + // * "Identify the network group with the most connections and youngest member. [...]" + } + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 6681c92bb5..66ad7bb5ea 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -4,14 +4,20 @@ #include <net_permissions.h> #include <netbase.h> +#include <protocol.h> +#include <serialize.h> +#include <streams.h> #include <test/util/setup_common.h> #include <util/strencodings.h> #include <util/translation.h> +#include <version.h> #include <string> #include <boost/test/unit_test.hpp> +using namespace std::literals; + BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup) static CNetAddr ResolveIP(const std::string& ip) @@ -220,8 +226,22 @@ BOOST_AUTO_TEST_CASE(subnet_test) // IPv4 address with IPv6 netmask or the other way around. BOOST_CHECK(!CSubNet(ResolveIP("1.1.1.1"), ResolveIP("ffff::")).IsValid()); BOOST_CHECK(!CSubNet(ResolveIP("::1"), ResolveIP("255.0.0.0")).IsValid()); - // Can't subnet TOR (or any other non-IPv4 and non-IPv6 network). - BOOST_CHECK(!CSubNet(ResolveIP("5wyqrzbvrdsumnok.onion"), ResolveIP("255.0.0.0")).IsValid()); + + // Create Non-IP subnets. + + const CNetAddr tor_addr{ + ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")}; + + subnet = CSubNet(tor_addr); + BOOST_CHECK(subnet.IsValid()); + BOOST_CHECK_EQUAL(subnet.ToString(), tor_addr.ToString()); + BOOST_CHECK(subnet.Match(tor_addr)); + BOOST_CHECK( + !subnet.Match(ResolveIP("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion"))); + BOOST_CHECK(!subnet.Match(ResolveIP("1.2.3.4"))); + + BOOST_CHECK(!CSubNet(tor_addr, 200).IsValid()); + BOOST_CHECK(!CSubNet(tor_addr, ResolveIP("255.0.0.0")).IsValid()); subnet = ResolveSubNet("1.2.3.4/255.255.255.255"); BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32"); @@ -427,20 +447,120 @@ BOOST_AUTO_TEST_CASE(netpermissions_test) BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters) { CNetAddr addr; - BOOST_CHECK(LookupHost(std::string("127.0.0.1", 9), addr, false)); - BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0", 10), addr, false)); - BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0example.com", 21), addr, false)); - BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0example.com\0", 22), addr, false)); + BOOST_CHECK(LookupHost("127.0.0.1"s, addr, false)); + BOOST_CHECK(!LookupHost("127.0.0.1\0"s, addr, false)); + BOOST_CHECK(!LookupHost("127.0.0.1\0example.com"s, addr, false)); + BOOST_CHECK(!LookupHost("127.0.0.1\0example.com\0"s, addr, false)); CSubNet ret; - BOOST_CHECK(LookupSubNet(std::string("1.2.3.0/24", 10), ret)); - BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0", 11), ret)); - BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com", 22), ret)); - BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com\0", 23), ret)); - // We only do subnetting for IPv4 and IPv6 - BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion", 22), ret)); - BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0", 23), ret)); - BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0example.com", 34), ret)); - BOOST_CHECK(!LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0example.com\0", 35), ret)); + BOOST_CHECK(LookupSubNet("1.2.3.0/24"s, ret)); + BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0"s, ret)); + BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com"s, ret)); + BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com\0"s, ret)); + BOOST_CHECK(LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret)); + BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0"s, ret)); + BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com"s, ret)); + BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com\0"s, ret)); +} + +// Since CNetAddr (un)ser is tested separately in net_tests.cpp here we only +// try a few edge cases for port, service flags and time. + +static const std::vector<CAddress> fixture_addresses({ + CAddress( + CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0 /* port */), + NODE_NONE, + 0x4966bc61U /* Fri Jan 9 02:54:25 UTC 2009 */ + ), + CAddress( + CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0x00f1 /* port */), + NODE_NETWORK, + 0x83766279U /* Tue Nov 22 11:22:33 UTC 2039 */ + ), + CAddress( + CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0xf1f2 /* port */), + static_cast<ServiceFlags>(NODE_WITNESS | NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED), + 0xffffffffU /* Sun Feb 7 06:28:15 UTC 2106 */ + ) +}); + +// fixture_addresses should equal to this when serialized in V1 format. +// When this is unserialized from V1 format it should equal to fixture_addresses. +static constexpr const char* stream_addrv1_hex = + "03" // number of entries + + "61bc6649" // time, Fri Jan 9 02:54:25 UTC 2009 + "0000000000000000" // service flags, NODE_NONE + "00000000000000000000000000000001" // address, fixed 16 bytes (IPv4 embedded in IPv6) + "0000" // port + + "79627683" // time, Tue Nov 22 11:22:33 UTC 2039 + "0100000000000000" // service flags, NODE_NETWORK + "00000000000000000000000000000001" // address, fixed 16 bytes (IPv6) + "00f1" // port + + "ffffffff" // time, Sun Feb 7 06:28:15 UTC 2106 + "4804000000000000" // service flags, NODE_WITNESS | NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED + "00000000000000000000000000000001" // address, fixed 16 bytes (IPv6) + "f1f2"; // port + +// fixture_addresses should equal to this when serialized in V2 format. +// When this is unserialized from V2 format it should equal to fixture_addresses. +static constexpr const char* stream_addrv2_hex = + "03" // number of entries + + "61bc6649" // time, Fri Jan 9 02:54:25 UTC 2009 + "00" // service flags, COMPACTSIZE(NODE_NONE) + "02" // network id, IPv6 + "10" // address length, COMPACTSIZE(16) + "00000000000000000000000000000001" // address + "0000" // port + + "79627683" // time, Tue Nov 22 11:22:33 UTC 2039 + "01" // service flags, COMPACTSIZE(NODE_NETWORK) + "02" // network id, IPv6 + "10" // address length, COMPACTSIZE(16) + "00000000000000000000000000000001" // address + "00f1" // port + + "ffffffff" // time, Sun Feb 7 06:28:15 UTC 2106 + "fd4804" // service flags, COMPACTSIZE(NODE_WITNESS | NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED) + "02" // network id, IPv6 + "10" // address length, COMPACTSIZE(16) + "00000000000000000000000000000001" // address + "f1f2"; // port + +BOOST_AUTO_TEST_CASE(caddress_serialize_v1) +{ + CDataStream s(SER_NETWORK, PROTOCOL_VERSION); + + s << fixture_addresses; + BOOST_CHECK_EQUAL(HexStr(s), stream_addrv1_hex); +} + +BOOST_AUTO_TEST_CASE(caddress_unserialize_v1) +{ + CDataStream s(ParseHex(stream_addrv1_hex), SER_NETWORK, PROTOCOL_VERSION); + std::vector<CAddress> addresses_unserialized; + + s >> addresses_unserialized; + BOOST_CHECK(fixture_addresses == addresses_unserialized); +} + +BOOST_AUTO_TEST_CASE(caddress_serialize_v2) +{ + CDataStream s(SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); + + s << fixture_addresses; + BOOST_CHECK_EQUAL(HexStr(s), stream_addrv2_hex); +} + +BOOST_AUTO_TEST_CASE(caddress_unserialize_v2) +{ + CDataStream s(ParseHex(stream_addrv2_hex), SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); + std::vector<CAddress> addresses_unserialized; + + s >> addresses_unserialized; + BOOST_CHECK(fixture_addresses == addresses_unserialized); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index ca49b89ad8..d5a4d3fd80 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* Test calculation of next difficulty target with no constraints applying */ BOOST_AUTO_TEST_CASE(get_next_work) { - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); int64_t nLastRetargetTime = 1261130161; // Block #30240 CBlockIndex pindexLast; pindexLast.nHeight = 32255; @@ -26,7 +26,7 @@ BOOST_AUTO_TEST_CASE(get_next_work) /* Test the constraint on the upper bound for next work */ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) { - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); int64_t nLastRetargetTime = 1231006505; // Block #0 CBlockIndex pindexLast; pindexLast.nHeight = 2015; @@ -38,7 +38,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) /* Test the constraint on the lower bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) { - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); int64_t nLastRetargetTime = 1279008237; // Block #66528 CBlockIndex pindexLast; pindexLast.nHeight = 68543; @@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) /* Test the constraint on the upper bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) { - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time CBlockIndex pindexLast; pindexLast.nHeight = 46367; @@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_negative_target) { - const auto consensus = CreateChainParams(CBaseChainParams::MAIN)->GetConsensus(); + const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus(); uint256 hash; unsigned int nBits; nBits = UintToArith256(consensus.powLimit).GetCompact(true); @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_negative_target) BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_overflow_target) { - const auto consensus = CreateChainParams(CBaseChainParams::MAIN)->GetConsensus(); + const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus(); uint256 hash; unsigned int nBits = ~0x00800000; hash.SetHex("0x1"); @@ -80,7 +80,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_overflow_target) BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_too_easy_target) { - const auto consensus = CreateChainParams(CBaseChainParams::MAIN)->GetConsensus(); + const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus(); uint256 hash; unsigned int nBits; arith_uint256 nBits_arith = UintToArith256(consensus.powLimit); @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_too_easy_target) BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_biger_hash_than_target) { - const auto consensus = CreateChainParams(CBaseChainParams::MAIN)->GetConsensus(); + const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus(); uint256 hash; unsigned int nBits; arith_uint256 hash_arith = UintToArith256(consensus.powLimit); @@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_biger_hash_than_target) BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_zero_target) { - const auto consensus = CreateChainParams(CBaseChainParams::MAIN)->GetConsensus(); + const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus(); uint256 hash; unsigned int nBits; arith_uint256 hash_arith{0}; @@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_zero_target) BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) { - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); std::vector<CBlockIndex> blocks(10000); for (int i = 0; i < 10000; i++) { blocks[i].pprev = i ? &blocks[i - 1] : nullptr; @@ -135,9 +135,9 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) } } -void sanity_check_chainparams(std::string chainName) +void sanity_check_chainparams(const ArgsManager& args, std::string chainName) { - const auto chainParams = CreateChainParams(chainName); + const auto chainParams = CreateChainParams(args, chainName); const auto consensus = chainParams->GetConsensus(); // hash genesis is correct @@ -164,22 +164,22 @@ void sanity_check_chainparams(std::string chainName) BOOST_AUTO_TEST_CASE(ChainParams_MAIN_sanity) { - sanity_check_chainparams(CBaseChainParams::MAIN); + sanity_check_chainparams(*m_node.args, CBaseChainParams::MAIN); } BOOST_AUTO_TEST_CASE(ChainParams_REGTEST_sanity) { - sanity_check_chainparams(CBaseChainParams::REGTEST); + sanity_check_chainparams(*m_node.args, CBaseChainParams::REGTEST); } BOOST_AUTO_TEST_CASE(ChainParams_TESTNET_sanity) { - sanity_check_chainparams(CBaseChainParams::TESTNET); + sanity_check_chainparams(*m_node.args, CBaseChainParams::TESTNET); } BOOST_AUTO_TEST_CASE(ChainParams_SIGNET_sanity) { - sanity_check_chainparams(CBaseChainParams::SIGNET); + sanity_check_chainparams(*m_node.args, CBaseChainParams::SIGNET); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp index 8c2712f764..c489ac04e9 100644 --- a/src/test/raii_event_tests.cpp +++ b/src/test/raii_event_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index a42608a66d..7da364d316 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -48,12 +48,14 @@ BOOST_AUTO_TEST_CASE(reverselock_errors) WAIT_LOCK(mutex, lock); #ifdef DEBUG_LOCKORDER + bool prev = g_debug_lockorder_abort; + g_debug_lockorder_abort = false; + // Make sure trying to reverse lock a previous lock fails - try { - REVERSE_LOCK(lock2); - BOOST_CHECK(false); // REVERSE_LOCK(lock2) succeeded - } catch(...) { } + BOOST_CHECK_EXCEPTION(REVERSE_LOCK(lock2), std::logic_error, HasReason("lock2 was not most recent critical section locked")); BOOST_CHECK(lock2.owns_lock()); + + g_debug_lockorder_abort = prev; #endif // Make sure trying to reverse lock an unlocked lock fails diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 9a490aaf6b..740b2c72db 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index 2e5a7549b7..21162356b8 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -9,6 +9,7 @@ #include <boost/test/unit_test.hpp> #include <boost/thread/thread.hpp> +#include <functional> #include <mutex> BOOST_AUTO_TEST_SUITE(scheduler_tests) diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index f6824a4e5e..856ec6346d 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector<unsigned char>(oneAndTwo.begin(), oneAndTwo.end()); txTo.vin[4].scriptSig << std::vector<unsigned char>(fifteenSigops.begin(), fifteenSigops.end()); - BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins)); + BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins, false)); // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txTo), coins), 22U); @@ -356,7 +356,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd1.vin[0].prevout.hash = txFrom.GetHash(); txToNonStd1.vin[0].scriptSig << std::vector<unsigned char>(sixteenSigops.begin(), sixteenSigops.end()); - BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins)); + BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins, false)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd1), coins), 16U); CMutableTransaction txToNonStd2; @@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd2.vin[0].prevout.hash = txFrom.GetHash(); txToNonStd2.vin[0].scriptSig << std::vector<unsigned char>(twentySigops.begin(), twentySigops.end()); - BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins)); + BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins, false)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd2), coins), 20U); } diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 1d6bcadf69..366385b619 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -183,23 +183,23 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) s.clear(); s << ToByteVector(pubkey) << OP_CHECKSIG; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<PKHash>(&address) && - *boost::get<PKHash>(&address) == PKHash(pubkey)); + BOOST_CHECK(std::get_if<PKHash>(&address) && + *std::get_if<PKHash>(&address) == PKHash(pubkey)); // TxoutType::PUBKEYHASH s.clear(); s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<PKHash>(&address) && - *boost::get<PKHash>(&address) == PKHash(pubkey)); + BOOST_CHECK(std::get_if<PKHash>(&address) && + *std::get_if<PKHash>(&address) == PKHash(pubkey)); // TxoutType::SCRIPTHASH CScript redeemScript(s); // initialize with leftover P2PKH script s.clear(); s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<ScriptHash>(&address) && - *boost::get<ScriptHash>(&address) == ScriptHash(redeemScript)); + BOOST_CHECK(std::get_if<ScriptHash>(&address) && + *std::get_if<ScriptHash>(&address) == ScriptHash(redeemScript)); // TxoutType::MULTISIG s.clear(); @@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) BOOST_CHECK(ExtractDestination(s, address)); WitnessV0KeyHash keyhash; CHash160().Write(pubkey).Finalize(keyhash); - BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash); + BOOST_CHECK(std::get_if<WitnessV0KeyHash>(&address) && *std::get_if<WitnessV0KeyHash>(&address) == keyhash); // TxoutType::WITNESS_V0_SCRIPTHASH s.clear(); @@ -225,7 +225,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin()); s << OP_0 << ToByteVector(scripthash); BOOST_CHECK(ExtractDestination(s, address)); - BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash); + BOOST_CHECK(std::get_if<WitnessV0ScriptHash>(&address) && *std::get_if<WitnessV0ScriptHash>(&address) == scripthash); // TxoutType::WITNESS_UNKNOWN with unknown version s.clear(); @@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) unk.length = 33; unk.version = 1; std::copy(pubkey.begin(), pubkey.end(), unk.program); - BOOST_CHECK(boost::get<WitnessUnknown>(&address) && *boost::get<WitnessUnknown>(&address) == unk); + BOOST_CHECK(std::get_if<WitnessUnknown>(&address) && *std::get_if<WitnessUnknown>(&address) == unk); } BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) @@ -259,8 +259,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEY); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && - *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); + BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) && + *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); // TxoutType::PUBKEYHASH s.clear(); @@ -269,8 +269,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEYHASH); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && - *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); + BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) && + *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); // TxoutType::SCRIPTHASH CScript redeemScript(s); // initialize with leftover P2PKH script @@ -280,8 +280,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TxoutType::SCRIPTHASH); BOOST_CHECK_EQUAL(addresses.size(), 1U); BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) && - *boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript)); + BOOST_CHECK(std::get_if<ScriptHash>(&addresses[0]) && + *std::get_if<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript)); // TxoutType::MULTISIG s.clear(); @@ -293,10 +293,10 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) BOOST_CHECK_EQUAL(whichType, TxoutType::MULTISIG); BOOST_CHECK_EQUAL(addresses.size(), 2U); BOOST_CHECK_EQUAL(nRequired, 2); - BOOST_CHECK(boost::get<PKHash>(&addresses[0]) && - *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); - BOOST_CHECK(boost::get<PKHash>(&addresses[1]) && - *boost::get<PKHash>(&addresses[1]) == PKHash(pubkeys[1])); + BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) && + *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0])); + BOOST_CHECK(std::get_if<PKHash>(&addresses[1]) && + *std::get_if<PKHash>(&addresses[1]) == PKHash(pubkeys[1])); // TxoutType::NULL_DATA s.clear(); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 0830743d61..25ca171b33 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -5,10 +5,12 @@ #include <test/data/script_tests.json.h> #include <core_io.h> +#include <fs.h> #include <key.h> #include <rpc/util.h> #include <script/script.h> #include <script/script_error.h> +#include <script/sigcache.h> #include <script/sign.h> #include <script/signingprovider.h> #include <streams.h> @@ -104,18 +106,18 @@ static ScriptErrorDesc script_errors[]={ static std::string FormatScriptError(ScriptError_t err) { - for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i) - if (script_errors[i].err == err) - return script_errors[i].name; + for (const auto& se : script_errors) + if (se.err == err) + return se.name; BOOST_ERROR("Unknown scripterror enumeration value, update script_errors in script_tests.cpp."); return ""; } -static ScriptError_t ParseScriptError(const std::string &name) +static ScriptError_t ParseScriptError(const std::string& name) { - for (unsigned int i=0; i<ARRAYLEN(script_errors); ++i) - if (script_errors[i].name == name) - return script_errors[i].err; + for (const auto& se : script_errors) + if (se.name == name) + return se.err; BOOST_ERROR("Unknown scripterror \"" << name << "\" in test description"); return SCRIPT_ERR_UNKNOWN_ERROR; } @@ -1339,14 +1341,12 @@ BOOST_AUTO_TEST_CASE(script_GetScriptAsm) BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); } -static CScript -ScriptFromHex(const char* hex) +static CScript ScriptFromHex(const std::string& str) { - std::vector<unsigned char> data = ParseHex(hex); + std::vector<unsigned char> data = ParseHex(str); return CScript(data.begin(), data.end()); } - BOOST_AUTO_TEST_CASE(script_FindAndDelete) { // Exercise the FindAndDelete functionality @@ -1470,6 +1470,36 @@ BOOST_AUTO_TEST_CASE(script_HasValidOps) BOOST_CHECK(!script.HasValidOps()); } +static CMutableTransaction TxFromHex(const std::string& str) +{ + CMutableTransaction tx; + VectorReader(SER_DISK, SERIALIZE_TRANSACTION_NO_WITNESS, ParseHex(str), 0) >> tx; + return tx; +} + +static std::vector<CTxOut> TxOutsFromJSON(const UniValue& univalue) +{ + assert(univalue.isArray()); + std::vector<CTxOut> prevouts; + for (size_t i = 0; i < univalue.size(); ++i) { + CTxOut txout; + VectorReader(SER_DISK, 0, ParseHex(univalue[i].get_str()), 0) >> txout; + prevouts.push_back(std::move(txout)); + } + return prevouts; +} + +static CScriptWitness ScriptWitnessFromJSON(const UniValue& univalue) +{ + assert(univalue.isArray()); + CScriptWitness scriptwitness; + for (size_t i = 0; i < univalue.size(); ++i) { + auto bytes = ParseHex(univalue[i].get_str()); + scriptwitness.stack.push_back(std::move(bytes)); + } + return scriptwitness; +} + #if defined(HAVE_CONSENSUS_LIB) /* Test simple (successful) usage of bitcoinconsensus_verify_script */ @@ -1610,5 +1640,108 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_invalid_flags) BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_INVALID_FLAGS); } -#endif +#endif // defined(HAVE_CONSENSUS_LIB) + +static std::vector<unsigned int> AllConsensusFlags() +{ + std::vector<unsigned int> ret; + + for (unsigned int i = 0; i < 128; ++i) { + unsigned int flag = 0; + if (i & 1) flag |= SCRIPT_VERIFY_P2SH; + if (i & 2) flag |= SCRIPT_VERIFY_DERSIG; + if (i & 4) flag |= SCRIPT_VERIFY_NULLDUMMY; + if (i & 8) flag |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + if (i & 16) flag |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; + if (i & 32) flag |= SCRIPT_VERIFY_WITNESS; + if (i & 64) flag |= SCRIPT_VERIFY_TAPROOT; + + // SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH + if (flag & SCRIPT_VERIFY_WITNESS && !(flag & SCRIPT_VERIFY_P2SH)) continue; + // SCRIPT_VERIFY_TAPROOT requires SCRIPT_VERIFY_WITNESS + if (flag & SCRIPT_VERIFY_TAPROOT && !(flag & SCRIPT_VERIFY_WITNESS)) continue; + + ret.push_back(flag); + } + + return ret; +} + +/** Precomputed list of all valid combinations of consensus-relevant script validation flags. */ +static const std::vector<unsigned int> ALL_CONSENSUS_FLAGS = AllConsensusFlags(); + +static void AssetTest(const UniValue& test) +{ + BOOST_CHECK(test.isObject()); + + CMutableTransaction mtx = TxFromHex(test["tx"].get_str()); + const std::vector<CTxOut> prevouts = TxOutsFromJSON(test["prevouts"]); + BOOST_CHECK(prevouts.size() == mtx.vin.size()); + size_t idx = test["index"].get_int64(); + unsigned int test_flags = ParseScriptFlags(test["flags"].get_str()); + bool fin = test.exists("final") && test["final"].get_bool(); + + if (test.exists("success")) { + mtx.vin[idx].scriptSig = ScriptFromHex(test["success"]["scriptSig"].get_str()); + mtx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["success"]["witness"]); + CTransaction tx(mtx); + PrecomputedTransactionData txdata; + txdata.Init(tx, std::vector<CTxOut>(prevouts)); + CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata); + for (const auto flags : ALL_CONSENSUS_FLAGS) { + // "final": true tests are valid for all flags. Others are only valid with flags that are + // a subset of test_flags. + if (fin || ((flags & test_flags) == flags)) { + bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr); + BOOST_CHECK(ret); + } + } + } + + if (test.exists("failure")) { + mtx.vin[idx].scriptSig = ScriptFromHex(test["failure"]["scriptSig"].get_str()); + mtx.vin[idx].scriptWitness = ScriptWitnessFromJSON(test["failure"]["witness"]); + CTransaction tx(mtx); + PrecomputedTransactionData txdata; + txdata.Init(tx, std::vector<CTxOut>(prevouts)); + CachingTransactionSignatureChecker txcheck(&tx, idx, prevouts[idx].nValue, true, txdata); + for (const auto flags : ALL_CONSENSUS_FLAGS) { + // If a test is supposed to fail with test_flags, it should also fail with any superset thereof. + if ((flags & test_flags) == test_flags) { + bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr); + BOOST_CHECK(!ret); + } + } + } +} + +BOOST_AUTO_TEST_CASE(script_assets_test) +{ + // See src/test/fuzz/script_assets_test_minimizer.cpp for information on how to generate + // the script_assets_test.json file used by this test. + + const char* dir = std::getenv("DIR_UNIT_TEST_DATA"); + BOOST_WARN_MESSAGE(dir != nullptr, "Variable DIR_UNIT_TEST_DATA unset, skipping script_assets_test"); + if (dir == nullptr) return; + auto path = fs::path(dir) / "script_assets_test.json"; + bool exists = fs::exists(path); + BOOST_WARN_MESSAGE(exists, "File $DIR_UNIT_TEST_DATA/script_assets_test.json not found, skipping script_assets_test"); + if (!exists) return; + fs::ifstream file(path); + BOOST_CHECK(file.is_open()); + file.seekg(0, std::ios::end); + size_t length = file.tellg(); + file.seekg(0, std::ios::beg); + std::string data(length, '\0'); + file.read(&data[0], data.size()); + UniValue tests = read_json(data); + BOOST_CHECK(tests.isArray()); + BOOST_CHECK(tests.size() > 0); + + for (size_t i = 0; i < tests.size(); i++) { + AssetTest(tests[i]); + } + file.close(); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index c509a252e0..8f5ee1e8e2 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp index 19029ebd3c..3e4d1dac9e 100644 --- a/src/test/sync_tests.cpp +++ b/src/test/sync_tests.cpp @@ -7,6 +7,8 @@ #include <boost/test/unit_test.hpp> +#include <mutex> + namespace { template <typename MutexType> void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2) @@ -29,6 +31,49 @@ void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2) BOOST_CHECK(!error_thrown); #endif } + +#ifdef DEBUG_LOCKORDER +template <typename MutexType> +void TestDoubleLock2(MutexType& m) +{ + ENTER_CRITICAL_SECTION(m); + LEAVE_CRITICAL_SECTION(m); +} + +template <typename MutexType> +void TestDoubleLock(bool should_throw) +{ + const bool prev = g_debug_lockorder_abort; + g_debug_lockorder_abort = false; + + MutexType m; + ENTER_CRITICAL_SECTION(m); + if (should_throw) { + BOOST_CHECK_EXCEPTION(TestDoubleLock2(m), std::logic_error, + HasReason("double lock detected")); + } else { + BOOST_CHECK_NO_THROW(TestDoubleLock2(m)); + } + LEAVE_CRITICAL_SECTION(m); + + BOOST_CHECK(LockStackEmpty()); + + g_debug_lockorder_abort = prev; +} +#endif /* DEBUG_LOCKORDER */ + +template <typename MutexType> +void TestInconsistentLockOrderDetected(MutexType& mutex1, MutexType& mutex2) NO_THREAD_SAFETY_ANALYSIS +{ + ENTER_CRITICAL_SECTION(mutex1); + ENTER_CRITICAL_SECTION(mutex2); +#ifdef DEBUG_LOCKORDER + BOOST_CHECK_EXCEPTION(LEAVE_CRITICAL_SECTION(mutex1), std::logic_error, HasReason("mutex1 was not most recent critical section locked")); +#endif // DEBUG_LOCKORDER + LEAVE_CRITICAL_SECTION(mutex2); + LEAVE_CRITICAL_SECTION(mutex1); + BOOST_CHECK(LockStackEmpty()); +} } // namespace BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup) @@ -55,4 +100,43 @@ BOOST_AUTO_TEST_CASE(potential_deadlock_detected) #endif } +/* Double lock would produce an undefined behavior. Thus, we only do that if + * DEBUG_LOCKORDER is activated to detect it. We don't want non-DEBUG_LOCKORDER + * build to produce tests that exhibit known undefined behavior. */ +#ifdef DEBUG_LOCKORDER +BOOST_AUTO_TEST_CASE(double_lock_mutex) +{ + TestDoubleLock<Mutex>(true /* should throw */); +} + +BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex) +{ + TestDoubleLock<RecursiveMutex>(false /* should not throw */); +} +#endif /* DEBUG_LOCKORDER */ + +BOOST_AUTO_TEST_CASE(inconsistent_lock_order_detected) +{ +#ifdef DEBUG_LOCKORDER + bool prev = g_debug_lockorder_abort; + g_debug_lockorder_abort = false; +#endif // DEBUG_LOCKORDER + + RecursiveMutex rmutex1, rmutex2; + TestInconsistentLockOrderDetected(rmutex1, rmutex2); + // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical) + // the lock tracking data must not have been broken by exception. + TestInconsistentLockOrderDetected(rmutex1, rmutex2); + + Mutex mutex1, mutex2; + TestInconsistentLockOrderDetected(mutex1, mutex2); + // By checking lock order consistency (CheckLastCritical) before any unlocking (LeaveCritical) + // the lock tracking data must not have been broken by exception. + TestInconsistentLockOrderDetected(mutex1, mutex2); + +#ifdef DEBUG_LOCKORDER + g_debug_lockorder_abort = prev; +#endif // DEBUG_LOCKORDER +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index a55145c738..ce555f7299 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 94b5dba913..1eb30c68d6 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -24,6 +24,7 @@ #include <util/strencodings.h> #include <validation.h> +#include <functional> #include <map> #include <string> @@ -57,6 +58,7 @@ static std::map<std::string, unsigned int> mapFlagNames = { {std::string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM}, {std::string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE}, {std::string("CONST_SCRIPTCODE"), (unsigned int)SCRIPT_VERIFY_CONST_SCRIPTCODE}, + {std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT}, }; unsigned int ParseScriptFlags(std::string strFlags) @@ -304,7 +306,7 @@ BOOST_AUTO_TEST_CASE(test_Get) t1.vout[0].nValue = 90*CENT; t1.vout[0].scriptPubKey << OP_1; - BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins)); + BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins, false)); } static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true) @@ -427,12 +429,10 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) // check all inputs concurrently, with the cache PrecomputedTransactionData txdata(tx); - boost::thread_group threadGroup; CCheckQueue<CScriptCheck> scriptcheckqueue(128); CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue); - for (int i=0; i<20; i++) - threadGroup.create_thread(std::bind(&CCheckQueue<CScriptCheck>::Thread, std::ref(scriptcheckqueue))); + scriptcheckqueue.StartWorkerThreads(20); std::vector<Coin> coins; for(uint32_t i = 0; i < mtx.vin.size(); i++) { @@ -454,9 +454,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) bool controlCheck = control.Wait(); assert(controlCheck); - - threadGroup.interrupt_all(); - threadGroup.join_all(); + scriptcheckqueue.StopWorkerThreads(); } SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutableTransaction& input2, const CTransactionRef tx) @@ -761,7 +759,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) // Only one TxoutType::NULL_DATA permitted in all cases t.vout.resize(2); t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[0].nValue = 0; t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); + t.vout[1].nValue = 0; reason.clear(); BOOST_CHECK(!IsStandardTx(CTransaction(t), reason)); BOOST_CHECK_EQUAL(reason, "multi-op-return"); diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp new file mode 100644 index 0000000000..1d137b03b1 --- /dev/null +++ b/src/test/txrequest_tests.cpp @@ -0,0 +1,738 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include <txrequest.h> +#include <uint256.h> + +#include <test/util/setup_common.h> + +#include <algorithm> +#include <functional> +#include <vector> + +#include <boost/test/unit_test.hpp> + +BOOST_FIXTURE_TEST_SUITE(txrequest_tests, BasicTestingSetup) + +namespace { + +constexpr std::chrono::microseconds MIN_TIME = std::chrono::microseconds::min(); +constexpr std::chrono::microseconds MAX_TIME = std::chrono::microseconds::max(); +constexpr std::chrono::microseconds MICROSECOND = std::chrono::microseconds{1}; +constexpr std::chrono::microseconds NO_TIME = std::chrono::microseconds{0}; + +/** An Action is a function to call at a particular (simulated) timestamp. */ +using Action = std::pair<std::chrono::microseconds, std::function<void()>>; + +/** Object that stores actions from multiple interleaved scenarios, and data shared across them. + * + * The Scenario below is used to fill this. + */ +struct Runner +{ + /** The TxRequestTracker being tested. */ + TxRequestTracker txrequest; + + /** List of actions to be executed (in order of increasing timestamp). */ + std::vector<Action> actions; + + /** Which node ids have been assigned already (to prevent reuse). */ + std::set<NodeId> peerset; + + /** Which txhashes have been assigned already (to prevent reuse). */ + std::set<uint256> txhashset; + + /** Which (peer, gtxid) combinations are known to be expired. These need to be accumulated here instead of + * checked directly in the GetRequestable return value to avoid introducing a dependency between the various + * parallel tests. */ + std::multiset<std::pair<NodeId, GenTxid>> expired; +}; + +std::chrono::microseconds RandomTime8s() { return std::chrono::microseconds{1 + InsecureRandBits(23)}; } +std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 + InsecureRandBits(45)}; } + +/** A proxy for a Runner that helps build a sequence of consecutive test actions on a TxRequestTracker. + * + * Each Scenario is a proxy through which actions for the (sequential) execution of various tests are added to a + * Runner. The actions from multiple scenarios are then run concurrently, resulting in these tests being performed + * against a TxRequestTracker in parallel. Every test has its own unique txhashes and NodeIds which are not + * reused in other tests, and thus they should be independent from each other. Running them in parallel however + * means that we verify the behavior (w.r.t. one test's txhashes and NodeIds) even when the state of the data + * structure is more complicated due to the presence of other tests. + */ +class Scenario +{ + Runner& m_runner; + std::chrono::microseconds m_now; + std::string m_testname; + +public: + Scenario(Runner& runner, std::chrono::microseconds starttime) : m_runner(runner), m_now(starttime) {} + + /** Set a name for the current test, to give more clear error messages. */ + void SetTestName(std::string testname) + { + m_testname = std::move(testname); + } + + /** Advance this Scenario's time; this affects the timestamps newly scheduled events get. */ + void AdvanceTime(std::chrono::microseconds amount) + { + assert(amount.count() >= 0); + m_now += amount; + } + + /** Schedule a ForgetTxHash call at the Scheduler's current time. */ + void ForgetTxHash(const uint256& txhash) + { + auto& runner = m_runner; + runner.actions.emplace_back(m_now, [=,&runner]() { + runner.txrequest.ForgetTxHash(txhash); + runner.txrequest.SanityCheck(); + }); + } + + /** Schedule a ReceivedInv call at the Scheduler's current time. */ + void ReceivedInv(NodeId peer, const GenTxid& gtxid, bool pref, std::chrono::microseconds reqtime) + { + auto& runner = m_runner; + runner.actions.emplace_back(m_now, [=,&runner]() { + runner.txrequest.ReceivedInv(peer, gtxid, pref, reqtime); + runner.txrequest.SanityCheck(); + }); + } + + /** Schedule a DisconnectedPeer call at the Scheduler's current time. */ + void DisconnectedPeer(NodeId peer) + { + auto& runner = m_runner; + runner.actions.emplace_back(m_now, [=,&runner]() { + runner.txrequest.DisconnectedPeer(peer); + runner.txrequest.SanityCheck(); + }); + } + + /** Schedule a RequestedTx call at the Scheduler's current time. */ + void RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds exptime) + { + auto& runner = m_runner; + runner.actions.emplace_back(m_now, [=,&runner]() { + runner.txrequest.RequestedTx(peer, txhash, exptime); + runner.txrequest.SanityCheck(); + }); + } + + /** Schedule a ReceivedResponse call at the Scheduler's current time. */ + void ReceivedResponse(NodeId peer, const uint256& txhash) + { + auto& runner = m_runner; + runner.actions.emplace_back(m_now, [=,&runner]() { + runner.txrequest.ReceivedResponse(peer, txhash); + runner.txrequest.SanityCheck(); + }); + } + + /** Schedule calls to verify the TxRequestTracker's state at the Scheduler's current time. + * + * @param peer The peer whose state will be inspected. + * @param expected The expected return value for GetRequestable(peer) + * @param candidates The expected return value CountCandidates(peer) + * @param inflight The expected return value CountInFlight(peer) + * @param completed The expected return value of Count(peer), minus candidates and inflight. + * @param checkname An arbitrary string to include in error messages, for test identificatrion. + * @param offset Offset with the current time to use (must be <= 0). This allows simulations of time going + * backwards (but note that the ordering of this event only follows the scenario's m_now. + */ + void Check(NodeId peer, const std::vector<GenTxid>& expected, size_t candidates, size_t inflight, + size_t completed, const std::string& checkname, + std::chrono::microseconds offset = std::chrono::microseconds{0}) + { + const auto comment = m_testname + " " + checkname; + auto& runner = m_runner; + const auto now = m_now; + assert(offset.count() <= 0); + runner.actions.emplace_back(m_now, [=,&runner]() { + std::vector<std::pair<NodeId, GenTxid>> expired_now; + auto ret = runner.txrequest.GetRequestable(peer, now + offset, &expired_now); + for (const auto& entry : expired_now) runner.expired.insert(entry); + runner.txrequest.SanityCheck(); + runner.txrequest.PostGetRequestableSanityCheck(now + offset); + size_t total = candidates + inflight + completed; + size_t real_total = runner.txrequest.Count(peer); + size_t real_candidates = runner.txrequest.CountCandidates(peer); + size_t real_inflight = runner.txrequest.CountInFlight(peer); + BOOST_CHECK_MESSAGE(real_total == total, strprintf("[" + comment + "] total %i (%i expected)", real_total, total)); + BOOST_CHECK_MESSAGE(real_inflight == inflight, strprintf("[" + comment + "] inflight %i (%i expected)", real_inflight, inflight)); + BOOST_CHECK_MESSAGE(real_candidates == candidates, strprintf("[" + comment + "] candidates %i (%i expected)", real_candidates, candidates)); + BOOST_CHECK_MESSAGE(ret == expected, "[" + comment + "] mismatching requestables"); + }); + } + + /** Verify that an announcement for gtxid by peer has expired some time before this check is scheduled. + * + * Every expected expiration should be accounted for through exactly one call to this function. + */ + void CheckExpired(NodeId peer, GenTxid gtxid) + { + const auto& testname = m_testname; + auto& runner = m_runner; + runner.actions.emplace_back(m_now, [=,&runner]() { + auto it = runner.expired.find(std::pair<NodeId, GenTxid>{peer, gtxid}); + BOOST_CHECK_MESSAGE(it != runner.expired.end(), "[" + testname + "] missing expiration"); + if (it != runner.expired.end()) runner.expired.erase(it); + }); + } + + /** Generate a random txhash, whose priorities for certain peers are constrained. + * + * For example, NewTxHash({{p1,p2,p3},{p2,p4,p5}}) will generate a txhash T such that both: + * - priority(p1,T) > priority(p2,T) > priority(p3,T) + * - priority(p2,T) > priority(p4,T) > priority(p5,T) + * where priority is the predicted internal TxRequestTracker's priority, assuming all announcements + * are within the same preferredness class. + */ + uint256 NewTxHash(const std::vector<std::vector<NodeId>>& orders = {}) + { + uint256 ret; + bool ok; + do { + ret = InsecureRand256(); + ok = true; + for (const auto& order : orders) { + for (size_t pos = 1; pos < order.size(); ++pos) { + uint64_t prio_prev = m_runner.txrequest.ComputePriority(ret, order[pos - 1], true); + uint64_t prio_cur = m_runner.txrequest.ComputePriority(ret, order[pos], true); + if (prio_prev <= prio_cur) { + ok = false; + break; + } + } + if (!ok) break; + } + if (ok) { + ok = m_runner.txhashset.insert(ret).second; + } + } while(!ok); + return ret; + } + + /** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */ + GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {}) + { + return {InsecureRandBool(), NewTxHash(orders)}; + } + + /** Generate a new random NodeId to use as peer. The same NodeId is never returned twice + * (across all Scenarios combined). */ + NodeId NewPeer() + { + bool ok; + NodeId ret; + do { + ret = InsecureRandBits(63); + ok = m_runner.peerset.insert(ret).second; + } while(!ok); + return ret; + } + + std::chrono::microseconds Now() const { return m_now; } +}; + +/** Add to scenario a test with a single tx announced by a single peer. + * + * config is an integer in [0, 32), which controls which variant of the test is used. + */ +void BuildSingleTest(Scenario& scenario, int config) +{ + auto peer = scenario.NewPeer(); + auto gtxid = scenario.NewGTxid(); + bool immediate = config & 1; + bool preferred = config & 2; + auto delay = immediate ? NO_TIME : RandomTime8s(); + + scenario.SetTestName(strprintf("Single(config=%i)", config)); + + // Receive an announcement, either immediately requestable or delayed. + scenario.ReceivedInv(peer, gtxid, preferred, immediate ? MIN_TIME : scenario.Now() + delay); + if (immediate) { + scenario.Check(peer, {gtxid}, 1, 0, 0, "s1"); + } else { + scenario.Check(peer, {}, 1, 0, 0, "s2"); + scenario.AdvanceTime(delay - MICROSECOND); + scenario.Check(peer, {}, 1, 0, 0, "s3"); + scenario.AdvanceTime(MICROSECOND); + scenario.Check(peer, {gtxid}, 1, 0, 0, "s4"); + } + + if (config >> 3) { // We'll request the transaction + scenario.AdvanceTime(RandomTime8s()); + auto expiry = RandomTime8s(); + scenario.Check(peer, {gtxid}, 1, 0, 0, "s5"); + scenario.RequestedTx(peer, gtxid.GetHash(), scenario.Now() + expiry); + scenario.Check(peer, {}, 0, 1, 0, "s6"); + + if ((config >> 3) == 1) { // The request will time out + scenario.AdvanceTime(expiry - MICROSECOND); + scenario.Check(peer, {}, 0, 1, 0, "s7"); + scenario.AdvanceTime(MICROSECOND); + scenario.Check(peer, {}, 0, 0, 0, "s8"); + scenario.CheckExpired(peer, gtxid); + return; + } else { + scenario.AdvanceTime(std::chrono::microseconds{InsecureRandRange(expiry.count())}); + scenario.Check(peer, {}, 0, 1, 0, "s9"); + if ((config >> 3) == 3) { // A response will arrive for the transaction + scenario.ReceivedResponse(peer, gtxid.GetHash()); + scenario.Check(peer, {}, 0, 0, 0, "s10"); + return; + } + } + } + + if (config & 4) { // The peer will go offline + scenario.DisconnectedPeer(peer); + } else { // The transaction is no longer needed + scenario.ForgetTxHash(gtxid.GetHash()); + } + scenario.Check(peer, {}, 0, 0, 0, "s11"); +} + +/** Add to scenario a test with a single tx announced by two peers, to verify the + * right peer is selected for requests. + * + * config is an integer in [0, 32), which controls which variant of the test is used. + */ +void BuildPriorityTest(Scenario& scenario, int config) +{ + scenario.SetTestName(strprintf("Priority(config=%i)", config)); + + // Two peers. They will announce in order {peer1, peer2}. + auto peer1 = scenario.NewPeer(), peer2 = scenario.NewPeer(); + // Construct a transaction that under random rules would be preferred by peer2 or peer1, + // depending on configuration. + bool prio1 = config & 1; + auto gtxid = prio1 ? scenario.NewGTxid({{peer1, peer2}}) : scenario.NewGTxid({{peer2, peer1}}); + bool pref1 = config & 2, pref2 = config & 4; + + scenario.ReceivedInv(peer1, gtxid, pref1, MIN_TIME); + scenario.Check(peer1, {gtxid}, 1, 0, 0, "p1"); + if (InsecureRandBool()) { + scenario.AdvanceTime(RandomTime8s()); + scenario.Check(peer1, {gtxid}, 1, 0, 0, "p2"); + } + + scenario.ReceivedInv(peer2, gtxid, pref2, MIN_TIME); + bool stage2_prio = + // At this point, peer2 will be given priority if: + // - It is preferred and peer1 is not + (pref2 && !pref1) || + // - They're in the same preference class, + // and the randomized priority favors peer2 over peer1. + (pref1 == pref2 && !prio1); + NodeId priopeer = stage2_prio ? peer2 : peer1, otherpeer = stage2_prio ? peer1 : peer2; + scenario.Check(otherpeer, {}, 1, 0, 0, "p3"); + scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p4"); + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.Check(otherpeer, {}, 1, 0, 0, "p5"); + scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p6"); + + // We possibly request from the selected peer. + if (config & 8) { + scenario.RequestedTx(priopeer, gtxid.GetHash(), MAX_TIME); + scenario.Check(priopeer, {}, 0, 1, 0, "p7"); + scenario.Check(otherpeer, {}, 1, 0, 0, "p8"); + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + } + + // The peer which was selected (or requested from) now goes offline, or a NOTFOUND is received from them. + if (config & 16) { + scenario.DisconnectedPeer(priopeer); + } else { + scenario.ReceivedResponse(priopeer, gtxid.GetHash()); + } + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.Check(priopeer, {}, 0, 0, !(config & 16), "p8"); + scenario.Check(otherpeer, {gtxid}, 1, 0, 0, "p9"); + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + + // Now the other peer goes offline. + scenario.DisconnectedPeer(otherpeer); + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.Check(peer1, {}, 0, 0, 0, "p10"); + scenario.Check(peer2, {}, 0, 0, 0, "p11"); +} + +/** Add to scenario a randomized test in which N peers announce the same transaction, to verify + * the order in which they are requested. */ +void BuildBigPriorityTest(Scenario& scenario, int peers) +{ + scenario.SetTestName(strprintf("BigPriority(peers=%i)", peers)); + + // We will have N peers announce the same transaction. + std::map<NodeId, bool> preferred; + std::vector<NodeId> pref_peers, npref_peers; + int num_pref = InsecureRandRange(peers + 1) ; // Some preferred, ... + int num_npref = peers - num_pref; // some not preferred. + for (int i = 0; i < num_pref; ++i) { + pref_peers.push_back(scenario.NewPeer()); + preferred[pref_peers.back()] = true; + } + for (int i = 0; i < num_npref; ++i) { + npref_peers.push_back(scenario.NewPeer()); + preferred[npref_peers.back()] = false; + } + // Make a list of all peers, in order of intended request order (concatenation of pref_peers and npref_peers). + std::vector<NodeId> request_order; + for (int i = 0; i < num_pref; ++i) request_order.push_back(pref_peers[i]); + for (int i = 0; i < num_npref; ++i) request_order.push_back(npref_peers[i]); + + // Determine the announcement order randomly. + std::vector<NodeId> announce_order = request_order; + Shuffle(announce_order.begin(), announce_order.end(), g_insecure_rand_ctx); + + // Find a gtxid whose txhash prioritization is consistent with the required ordering within pref_peers and + // within npref_peers. + auto gtxid = scenario.NewGTxid({pref_peers, npref_peers}); + + // Decide reqtimes in opposite order of the expected request order. This means that as time passes we expect the + // to-be-requested-from-peer will change every time a subsequent reqtime is passed. + std::map<NodeId, std::chrono::microseconds> reqtimes; + auto reqtime = scenario.Now(); + for (int i = peers - 1; i >= 0; --i) { + reqtime += RandomTime8s(); + reqtimes[request_order[i]] = reqtime; + } + + // Actually announce from all peers simultaneously (but in announce_order). + for (const auto peer : announce_order) { + scenario.ReceivedInv(peer, gtxid, preferred[peer], reqtimes[peer]); + } + for (const auto peer : announce_order) { + scenario.Check(peer, {}, 1, 0, 0, "b1"); + } + + // Let time pass and observe the to-be-requested-from peer change, from nonpreferred to preferred, and from + // high priority to low priority within each class. + for (int i = peers - 1; i >= 0; --i) { + scenario.AdvanceTime(reqtimes[request_order[i]] - scenario.Now() - MICROSECOND); + scenario.Check(request_order[i], {}, 1, 0, 0, "b2"); + scenario.AdvanceTime(MICROSECOND); + scenario.Check(request_order[i], {gtxid}, 1, 0, 0, "b3"); + } + + // Peers now in random order go offline, or send NOTFOUNDs. At every point in time the new to-be-requested-from + // peer should be the best remaining one, so verify this after every response. + for (int i = 0; i < peers; ++i) { + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + const int pos = InsecureRandRange(request_order.size()); + const auto peer = request_order[pos]; + request_order.erase(request_order.begin() + pos); + if (InsecureRandBool()) { + scenario.DisconnectedPeer(peer); + scenario.Check(peer, {}, 0, 0, 0, "b4"); + } else { + scenario.ReceivedResponse(peer, gtxid.GetHash()); + scenario.Check(peer, {}, 0, 0, request_order.size() > 0, "b5"); + } + if (request_order.size()) { + scenario.Check(request_order[0], {gtxid}, 1, 0, 0, "b6"); + } + } + + // Everything is gone in the end. + for (const auto peer : announce_order) { + scenario.Check(peer, {}, 0, 0, 0, "b7"); + } +} + +/** Add to scenario a test with one peer announcing two transactions, to verify they are + * fetched in announcement order. + * + * config is an integer in [0, 4) inclusive, and selects the variant of the test. + */ +void BuildRequestOrderTest(Scenario& scenario, int config) +{ + scenario.SetTestName(strprintf("RequestOrder(config=%i)", config)); + + auto peer = scenario.NewPeer(); + auto gtxid1 = scenario.NewGTxid(); + auto gtxid2 = scenario.NewGTxid(); + + auto reqtime2 = scenario.Now() + RandomTime8s(); + auto reqtime1 = reqtime2 + RandomTime8s(); + + scenario.ReceivedInv(peer, gtxid1, config & 1, reqtime1); + // Simulate time going backwards by giving the second announcement an earlier reqtime. + scenario.ReceivedInv(peer, gtxid2, config & 2, reqtime2); + + scenario.AdvanceTime(reqtime2 - MICROSECOND - scenario.Now()); + scenario.Check(peer, {}, 2, 0, 0, "o1"); + scenario.AdvanceTime(MICROSECOND); + scenario.Check(peer, {gtxid2}, 2, 0, 0, "o2"); + scenario.AdvanceTime(reqtime1 - MICROSECOND - scenario.Now()); + scenario.Check(peer, {gtxid2}, 2, 0, 0, "o3"); + scenario.AdvanceTime(MICROSECOND); + // Even with time going backwards in between announcements, the return value of GetRequestable is in + // announcement order. + scenario.Check(peer, {gtxid1, gtxid2}, 2, 0, 0, "o4"); + + scenario.DisconnectedPeer(peer); + scenario.Check(peer, {}, 0, 0, 0, "o5"); +} + +/** Add to scenario a test that verifies behavior related to both txid and wtxid with the same + * hash being announced. + * + * config is an integer in [0, 4) inclusive, and selects the variant of the test used. +*/ +void BuildWtxidTest(Scenario& scenario, int config) +{ + scenario.SetTestName(strprintf("Wtxid(config=%i)", config)); + + auto peerT = scenario.NewPeer(); + auto peerW = scenario.NewPeer(); + auto txhash = scenario.NewTxHash(); + GenTxid txid{false, txhash}; + GenTxid wtxid{true, txhash}; + + auto reqtimeT = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); + auto reqtimeW = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); + + // Announce txid first or wtxid first. + if (config & 1) { + scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT); + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW); + } else { + scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW); + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT); + } + + // Let time pass if needed, and check that the preferred announcement (txid or wtxid) + // is correctly to-be-requested (and with the correct wtxidness). + auto max_reqtime = std::max(reqtimeT, reqtimeW); + if (max_reqtime > scenario.Now()) scenario.AdvanceTime(max_reqtime - scenario.Now()); + if (config & 2) { + scenario.Check(peerT, {txid}, 1, 0, 0, "w1"); + scenario.Check(peerW, {}, 1, 0, 0, "w2"); + } else { + scenario.Check(peerT, {}, 1, 0, 0, "w3"); + scenario.Check(peerW, {wtxid}, 1, 0, 0, "w4"); + } + + // Let the preferred announcement be requested. It's not going to be delivered. + auto expiry = RandomTime8s(); + if (config & 2) { + scenario.RequestedTx(peerT, txid.GetHash(), scenario.Now() + expiry); + scenario.Check(peerT, {}, 0, 1, 0, "w5"); + scenario.Check(peerW, {}, 1, 0, 0, "w6"); + } else { + scenario.RequestedTx(peerW, wtxid.GetHash(), scenario.Now() + expiry); + scenario.Check(peerT, {}, 1, 0, 0, "w7"); + scenario.Check(peerW, {}, 0, 1, 0, "w8"); + } + + // After reaching expiration time of the preferred announcement, verify that the + // remaining one is requestable + scenario.AdvanceTime(expiry); + if (config & 2) { + scenario.Check(peerT, {}, 0, 0, 1, "w9"); + scenario.Check(peerW, {wtxid}, 1, 0, 0, "w10"); + scenario.CheckExpired(peerT, txid); + } else { + scenario.Check(peerT, {txid}, 1, 0, 0, "w11"); + scenario.Check(peerW, {}, 0, 0, 1, "w12"); + scenario.CheckExpired(peerW, wtxid); + } + + // If a good transaction with either that hash as wtxid or txid arrives, both + // announcements are gone. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.ForgetTxHash(txhash); + scenario.Check(peerT, {}, 0, 0, 0, "w13"); + scenario.Check(peerW, {}, 0, 0, 0, "w14"); +} + +/** Add to scenario a test that exercises clocks that go backwards. */ +void BuildTimeBackwardsTest(Scenario& scenario) +{ + auto peer1 = scenario.NewPeer(); + auto peer2 = scenario.NewPeer(); + auto gtxid = scenario.NewGTxid({{peer1, peer2}}); + + // Announce from peer2. + auto reqtime = scenario.Now() + RandomTime8s(); + scenario.ReceivedInv(peer2, gtxid, true, reqtime); + scenario.Check(peer2, {}, 1, 0, 0, "r1"); + scenario.AdvanceTime(reqtime - scenario.Now()); + scenario.Check(peer2, {gtxid}, 1, 0, 0, "r2"); + // Check that if the clock goes backwards by 1us, the transaction would stop being requested. + scenario.Check(peer2, {}, 1, 0, 0, "r3", -MICROSECOND); + // But it reverts to being requested if time goes forward again. + scenario.Check(peer2, {gtxid}, 1, 0, 0, "r4"); + + // Announce from peer1. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.ReceivedInv(peer1, gtxid, true, MAX_TIME); + scenario.Check(peer2, {gtxid}, 1, 0, 0, "r5"); + scenario.Check(peer1, {}, 1, 0, 0, "r6"); + + // Request from peer1. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + auto expiry = scenario.Now() + RandomTime8s(); + scenario.RequestedTx(peer1, gtxid.GetHash(), expiry); + scenario.Check(peer1, {}, 0, 1, 0, "r7"); + scenario.Check(peer2, {}, 1, 0, 0, "r8"); + + // Expiration passes. + scenario.AdvanceTime(expiry - scenario.Now()); + scenario.Check(peer1, {}, 0, 0, 1, "r9"); + scenario.Check(peer2, {gtxid}, 1, 0, 0, "r10"); // Request goes back to peer2. + scenario.CheckExpired(peer1, gtxid); + scenario.Check(peer1, {}, 0, 0, 1, "r11", -MICROSECOND); // Going back does not unexpire. + scenario.Check(peer2, {gtxid}, 1, 0, 0, "r12", -MICROSECOND); + + // Peer2 goes offline, meaning no viable announcements remain. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.DisconnectedPeer(peer2); + scenario.Check(peer1, {}, 0, 0, 0, "r13"); + scenario.Check(peer2, {}, 0, 0, 0, "r14"); +} + +/** Add to scenario a test that involves RequestedTx() calls for txhashes not returned by GetRequestable. */ +void BuildWeirdRequestsTest(Scenario& scenario) +{ + auto peer1 = scenario.NewPeer(); + auto peer2 = scenario.NewPeer(); + auto gtxid1 = scenario.NewGTxid({{peer1, peer2}}); + auto gtxid2 = scenario.NewGTxid({{peer2, peer1}}); + + // Announce gtxid1 by peer1. + scenario.ReceivedInv(peer1, gtxid1, true, MIN_TIME); + scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q1"); + + // Announce gtxid2 by peer2. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.ReceivedInv(peer2, gtxid2, true, MIN_TIME); + scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q2"); + scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q3"); + + // We request gtxid2 from *peer1* - no effect. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); + scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4"); + scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5"); + + // Now request gtxid1 from peer1 - marks it as REQUESTED. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + auto expiryA = scenario.Now() + RandomTime8s(); + scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA); + scenario.Check(peer1, {}, 0, 1, 0, "q6"); + scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q7"); + + // Request it a second time - nothing happens, as it's already REQUESTED. + auto expiryB = expiryA + RandomTime8s(); + scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryB); + scenario.Check(peer1, {}, 0, 1, 0, "q8"); + scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q9"); + + // Also announce gtxid1 from peer2 now, so that the txhash isn't forgotten when the peer1 request expires. + scenario.ReceivedInv(peer2, gtxid1, true, MIN_TIME); + scenario.Check(peer1, {}, 0, 1, 0, "q10"); + scenario.Check(peer2, {gtxid2}, 2, 0, 0, "q11"); + + // When reaching expiryA, it expires (not expiryB, which is later). + scenario.AdvanceTime(expiryA - scenario.Now()); + scenario.Check(peer1, {}, 0, 0, 1, "q12"); + scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q13"); + scenario.CheckExpired(peer1, gtxid1); + + // Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.RequestedTx(peer1, gtxid1.GetHash(), MAX_TIME); + scenario.Check(peer1, {}, 0, 0, 1, "q14"); + scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15"); + + // Now announce gtxid2 from peer1. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.ReceivedInv(peer1, gtxid2, true, MIN_TIME); + scenario.Check(peer1, {}, 1, 0, 1, "q16"); + scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q17"); + + // And request it from peer1 (weird as peer2 has the preference). + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); + scenario.Check(peer1, {}, 0, 1, 1, "q18"); + scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19"); + + // If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED. + if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + scenario.RequestedTx(peer2, gtxid2.GetHash(), MAX_TIME); + scenario.Check(peer1, {}, 0, 0, 2, "q20"); + scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21"); + + // If peer2 goes offline, no viable announcements remain. + scenario.DisconnectedPeer(peer2); + scenario.Check(peer1, {}, 0, 0, 0, "q22"); + scenario.Check(peer2, {}, 0, 0, 0, "q23"); +} + +void TestInterleavedScenarios() +{ + // Create a list of functions which add tests to scenarios. + std::vector<std::function<void(Scenario&)>> builders; + // Add instances of every test, for every configuration. + for (int n = 0; n < 64; ++n) { + builders.emplace_back([n](Scenario& scenario){ BuildWtxidTest(scenario, n); }); + builders.emplace_back([n](Scenario& scenario){ BuildRequestOrderTest(scenario, n & 3); }); + builders.emplace_back([n](Scenario& scenario){ BuildSingleTest(scenario, n & 31); }); + builders.emplace_back([n](Scenario& scenario){ BuildPriorityTest(scenario, n & 31); }); + builders.emplace_back([n](Scenario& scenario){ BuildBigPriorityTest(scenario, (n & 7) + 1); }); + builders.emplace_back([](Scenario& scenario){ BuildTimeBackwardsTest(scenario); }); + builders.emplace_back([](Scenario& scenario){ BuildWeirdRequestsTest(scenario); }); + } + // Randomly shuffle all those functions. + Shuffle(builders.begin(), builders.end(), g_insecure_rand_ctx); + + Runner runner; + auto starttime = RandomTime1y(); + // Construct many scenarios, and run (up to) 10 randomly-chosen tests consecutively in each. + while (builders.size()) { + // Introduce some variation in the start time of each scenario, so they don't all start off + // concurrently, but get a more random interleaving. + auto scenario_start = starttime + RandomTime8s() + RandomTime8s() + RandomTime8s(); + Scenario scenario(runner, scenario_start); + for (int j = 0; builders.size() && j < 10; ++j) { + builders.back()(scenario); + builders.pop_back(); + } + } + // Sort all the actions from all those scenarios chronologically, resulting in the actions from + // distinct scenarios to become interleaved. Use stable_sort so that actions from one scenario + // aren't reordered w.r.t. each other. + std::stable_sort(runner.actions.begin(), runner.actions.end(), [](const Action& a1, const Action& a2) { + return a1.first < a2.first; + }); + + // Run all actions from all scenarios, in order. + for (auto& action : runner.actions) { + action.second(); + } + + BOOST_CHECK_EQUAL(runner.txrequest.Size(), 0U); + BOOST_CHECK(runner.expired.empty()); +} + +} // namespace + +BOOST_AUTO_TEST_CASE(TxRequestTest) +{ + for (int i = 0; i < 5; ++i) { + TestInterleavedScenarios(); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp index c3d7af8323..7e6246d68f 100644 --- a/src/test/txvalidation_tests.cpp +++ b/src/test/txvalidation_tests.cpp @@ -40,8 +40,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup) false, AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(coinbaseTx), nullptr /* plTxnReplaced */, - true /* bypass_limits */, - 0 /* nAbsurdFee */)); + true /* bypass_limits */)); // Check that the transaction hasn't been added to mempool. BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize); diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 034577aa2c..bed2ba3608 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) TxValidationState state; return AcceptToMemoryPool(*m_node.mempool, state, MakeTransactionRef(tx), - nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */); + nullptr /* plTxnReplaced */, true /* bypass_limits */); }; // Create a double-spend of mature coinbase txn: diff --git a/src/test/util/logging.cpp b/src/test/util/logging.cpp index 65a64f2384..c1dd47f06c 100644 --- a/src/test/util/logging.cpp +++ b/src/test/util/logging.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/logging.h b/src/test/util/logging.h index 1fcf7ca305..ebe0ecf623 100644 --- a/src/test/util/logging.h +++ b/src/test/util/logging.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -32,7 +32,7 @@ class DebugLogHelper void check_found(); public: - DebugLogHelper(std::string message, MatchFn match = [](const std::string*){ return true; }); + explicit DebugLogHelper(std::string message, MatchFn match = [](const std::string*){ return true; }); ~DebugLogHelper() { check_found(); } }; diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index 74536ae74c..0c6487fbfa 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp index 09f2f1807f..847a490e03 100644 --- a/src/test/util/net.cpp +++ b/src/test/util/net.cpp @@ -7,9 +7,9 @@ #include <chainparams.h> #include <net.h> -void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, const char* pch, unsigned int nBytes, bool& complete) const +void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, Span<const uint8_t> msg_bytes, bool& complete) const { - assert(node.ReceiveMsgBytes(pch, nBytes, complete)); + assert(node.ReceiveMsgBytes(msg_bytes, complete)); if (complete) { size_t nSizeAdded = 0; auto it(node.vRecvMsg.begin()); @@ -29,11 +29,11 @@ void ConnmanTestMsg::NodeReceiveMsgBytes(CNode& node, const char* pch, unsigned bool ConnmanTestMsg::ReceiveMsgFrom(CNode& node, CSerializedNetMsg& ser_msg) const { - std::vector<unsigned char> ser_msg_header; + std::vector<uint8_t> ser_msg_header; node.m_serializer->prepareForTransport(ser_msg, ser_msg_header); bool complete; - NodeReceiveMsgBytes(node, (const char*)ser_msg_header.data(), ser_msg_header.size(), complete); - NodeReceiveMsgBytes(node, (const char*)ser_msg.data.data(), ser_msg.data.size(), complete); + NodeReceiveMsgBytes(node, ser_msg_header, complete); + NodeReceiveMsgBytes(node, ser_msg.data, complete); return complete; } diff --git a/src/test/util/net.h b/src/test/util/net.h index ca8cb7fad5..e25036be26 100644 --- a/src/test/util/net.h +++ b/src/test/util/net.h @@ -25,9 +25,40 @@ struct ConnmanTestMsg : public CConnman { void ProcessMessagesOnce(CNode& node) { m_msgproc->ProcessMessages(&node, flagInterruptMsgProc); } - void NodeReceiveMsgBytes(CNode& node, const char* pch, unsigned int nBytes, bool& complete) const; + void NodeReceiveMsgBytes(CNode& node, Span<const uint8_t> msg_bytes, bool& complete) const; bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg& ser_msg) const; }; +constexpr ServiceFlags ALL_SERVICE_FLAGS[]{ + NODE_NONE, + NODE_NETWORK, + NODE_BLOOM, + NODE_WITNESS, + NODE_COMPACT_FILTERS, + NODE_NETWORK_LIMITED, +}; + +constexpr NetPermissionFlags ALL_NET_PERMISSION_FLAGS[]{ + NetPermissionFlags::PF_NONE, + NetPermissionFlags::PF_BLOOMFILTER, + NetPermissionFlags::PF_RELAY, + NetPermissionFlags::PF_FORCERELAY, + NetPermissionFlags::PF_NOBAN, + NetPermissionFlags::PF_MEMPOOL, + NetPermissionFlags::PF_ADDR, + NetPermissionFlags::PF_DOWNLOAD, + NetPermissionFlags::PF_ISIMPLICIT, + NetPermissionFlags::PF_ALL, +}; + +constexpr ConnectionType ALL_CONNECTION_TYPES[]{ + ConnectionType::INBOUND, + ConnectionType::OUTBOUND_FULL_RELAY, + ConnectionType::MANUAL, + ConnectionType::FEELER, + ConnectionType::BLOCK_RELAY, + ConnectionType::ADDR_FETCH, +}; + #endif // BITCOIN_TEST_UTIL_NET_H diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 2d3137e1e2..8a9694f55b 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -16,6 +16,7 @@ #include <net.h> #include <net_processing.h> #include <noui.h> +#include <policy/fees.h> #include <pow.h> #include <rpc/blockchain.h> #include <rpc/register.h> @@ -124,27 +125,55 @@ BasicTestingSetup::~BasicTestingSetup() ECC_Stop(); } -TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args) +ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args) : BasicTestingSetup(chainName, extra_args) { - const CChainParams& chainparams = Params(); - // Ideally we'd move all the RPC tests to the functional testing framework - // instead of unit tests, but for now we need these here. - RegisterAllCoreRPCCommands(tableRPC); - - m_node.scheduler = MakeUnique<CScheduler>(); - // We have to run a scheduler thread to prevent ActivateBestChain // from blocking due to queue overrun. + m_node.scheduler = MakeUnique<CScheduler>(); threadGroup.create_thread([&] { TraceThread("scheduler", [&] { m_node.scheduler->serviceQueue(); }); }); GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler); pblocktree.reset(new CBlockTreeDB(1 << 20, true)); - m_node.mempool = MakeUnique<CTxMemPool>(&::feeEstimator); - m_node.mempool->setSanityCheck(1.0); + m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(); + m_node.mempool = std::make_unique<CTxMemPool>(m_node.fee_estimator.get(), 1); m_node.chainman = &::g_chainman; + + // Start script-checking threads. Set g_parallel_script_checks to true so they are used. + constexpr int script_check_threads = 2; + StartScriptCheckWorkerThreads(script_check_threads); + g_parallel_script_checks = true; +} + +ChainTestingSetup::~ChainTestingSetup() +{ + if (m_node.scheduler) m_node.scheduler->stop(); + threadGroup.interrupt_all(); + threadGroup.join_all(); + StopScriptCheckWorkerThreads(); + GetMainSignals().FlushBackgroundCallbacks(); + GetMainSignals().UnregisterBackgroundSignalScheduler(); + m_node.connman.reset(); + m_node.banman.reset(); + m_node.args = nullptr; + UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman); + m_node.mempool.reset(); + m_node.scheduler.reset(); + m_node.chainman->Reset(); + m_node.chainman = nullptr; + pblocktree.reset(); +} + +TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const char*>& extra_args) + : ChainTestingSetup(chainName, extra_args) +{ + const CChainParams& chainparams = Params(); + // Ideally we'd move all the RPC tests to the functional testing framework + // instead of unit tests, but for now we need these here. + RegisterAllCoreRPCCommands(tableRPC); + m_node.chainman->InitializeChainstate(*m_node.mempool); ::ChainstateActive().InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); @@ -160,16 +189,11 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString())); } - // Start script-checking threads. Set g_parallel_script_checks to true so they are used. - constexpr int script_check_threads = 2; - for (int i = 0; i < script_check_threads; ++i) { - threadGroup.create_thread([i]() { return ThreadScriptCheck(i); }); - } - g_parallel_script_checks = true; - m_node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests. - m_node.peerman = MakeUnique<PeerManager>(chainparams, *m_node.connman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool); + m_node.peerman = PeerManager::make(chainparams, *m_node.connman, m_node.banman.get(), + *m_node.scheduler, *m_node.chainman, *m_node.mempool, + false); { CConnman::Options options; options.m_msgproc = m_node.peerman.get(); @@ -177,24 +201,6 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const } } -TestingSetup::~TestingSetup() -{ - if (m_node.scheduler) m_node.scheduler->stop(); - threadGroup.interrupt_all(); - threadGroup.join_all(); - GetMainSignals().FlushBackgroundCallbacks(); - GetMainSignals().UnregisterBackgroundSignalScheduler(); - m_node.connman.reset(); - m_node.banman.reset(); - m_node.args = nullptr; - UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman); - m_node.mempool.reset(); - m_node.scheduler.reset(); - m_node.chainman->Reset(); - m_node.chainman = nullptr; - pblocktree.reset(); -} - TestChain100Setup::TestChain100Setup() { // Generate a 100-block chain: @@ -232,12 +238,12 @@ TestChain100Setup::~TestChain100Setup() gArgs.ForceSetArg("-segwitheight", "0"); } -CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const { return FromTx(MakeTransactionRef(tx)); } -CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx) +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx) const { return CTxMemPoolEntry(tx, nFee, nTime, nHeight, spendsCoinbase, sigOpCost, lp); diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index a09c8c122d..dff8cf825e 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -11,6 +11,7 @@ #include <node/context.h> #include <pubkey.h> #include <random.h> +#include <stdexcept> #include <txmempool.h> #include <util/check.h> #include <util/string.h> @@ -82,14 +83,21 @@ private: const fs::path m_path_root; }; -/** Testing setup that configures a complete environment. - * Included are coins database, script check threads setup. +/** Testing setup that performs all steps up until right before + * ChainstateManager gets initialized. Meant for testing ChainstateManager + * initialization behaviour. */ -struct TestingSetup : public BasicTestingSetup { +struct ChainTestingSetup : public BasicTestingSetup { boost::thread_group threadGroup; + explicit ChainTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {}); + ~ChainTestingSetup(); +}; + +/** Testing setup that configures a complete environment. + */ +struct TestingSetup : public ChainTestingSetup { explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {}); - ~TestingSetup(); }; /** Identical to TestingSetup, but chain set to regtest */ @@ -137,8 +145,8 @@ struct TestMemPoolEntryHelper nFee(0), nTime(0), nHeight(1), spendsCoinbase(false), sigOpCost(4) { } - CTxMemPoolEntry FromTx(const CMutableTransaction& tx); - CTxMemPoolEntry FromTx(const CTransactionRef& tx); + CTxMemPoolEntry FromTx(const CMutableTransaction& tx) const; + CTxMemPoolEntry FromTx(const CTransactionRef& tx) const; // Change the default value TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; } @@ -158,13 +166,15 @@ std::ostream& operator<<(std::ostream& os, const uint256& num); * Use as * BOOST_CHECK_EXCEPTION(code that throws, exception type, HasReason("foo")); */ -class HasReason { +class HasReason +{ public: explicit HasReason(const std::string& reason) : m_reason(reason) {} - template <typename E> - bool operator() (const E& e) const { + bool operator()(const std::exception& e) const + { return std::string(e.what()).find(m_reason) != std::string::npos; }; + private: const std::string m_reason; }; diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp new file mode 100644 index 0000000000..1aed492c3c --- /dev/null +++ b/src/test/util/validation.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <test/util/validation.h> + +#include <util/check.h> +#include <util/time.h> +#include <validation.h> + +void TestChainState::ResetIbd() +{ + m_cached_finished_ibd = false; + assert(IsInitialBlockDownload()); +} + +void TestChainState::JumpOutOfIbd() +{ + Assert(IsInitialBlockDownload()); + m_cached_finished_ibd = true; + Assert(!IsInitialBlockDownload()); +} diff --git a/src/test/util/validation.h b/src/test/util/validation.h new file mode 100644 index 0000000000..b13aa0be60 --- /dev/null +++ b/src/test/util/validation.h @@ -0,0 +1,17 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TEST_UTIL_VALIDATION_H +#define BITCOIN_TEST_UTIL_VALIDATION_H + +#include <validation.h> + +struct TestChainState : public CChainState { + /** Reset the ibd cache to its initial state */ + void ResetIbd(); + /** Toggle IsInitialBlockDownload from true to false */ + void JumpOutOfIbd(); +}; + +#endif // BITCOIN_TEST_UTIL_VALIDATION_H diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 241c56934e..4133f2623b 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -23,6 +23,7 @@ #include <array> #include <stdint.h> +#include <string.h> #include <thread> #include <univalue.h> #include <utility> @@ -35,6 +36,8 @@ #include <boost/test/unit_test.hpp> +using namespace std::literals; + /* defined in logging.cpp */ namespace BCLog { std::string LogEscapeMessage(const std::string& str); @@ -42,6 +45,28 @@ namespace BCLog { BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) +BOOST_AUTO_TEST_CASE(util_datadir) +{ + ClearDatadirCache(); + const fs::path dd_norm = GetDataDir(); + + gArgs.ForceSetArg("-datadir", dd_norm.string() + "/"); + ClearDatadirCache(); + BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + + gArgs.ForceSetArg("-datadir", dd_norm.string() + "/."); + ClearDatadirCache(); + BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + + gArgs.ForceSetArg("-datadir", dd_norm.string() + "/./"); + ClearDatadirCache(); + BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); + + gArgs.ForceSetArg("-datadir", dd_norm.string() + "/.//"); + ClearDatadirCache(); + BOOST_CHECK_EQUAL(dd_norm, GetDataDir()); +} + BOOST_AUTO_TEST_CASE(util_check) { // Check that Assert can forward @@ -206,7 +231,7 @@ public: Optional<std::vector<std::string>> list_value; const char* error = nullptr; - Expect(util::SettingsValue s) : setting(std::move(s)) {} + explicit Expect(util::SettingsValue s) : setting(std::move(s)) {} Expect& DefaultString() { default_string = true; return *this; } Expect& DefaultInt() { default_int = true; return *this; } Expect& DefaultBool() { default_bool = true; return *this; } @@ -1235,9 +1260,9 @@ BOOST_AUTO_TEST_CASE(util_ParseMoney) BOOST_CHECK(!ParseMoney("-1", ret)); // Parsing strings with embedded NUL characters should fail - BOOST_CHECK(!ParseMoney(std::string("\0-1", 3), ret)); - BOOST_CHECK(!ParseMoney(std::string("\01", 2), ret)); - BOOST_CHECK(!ParseMoney(std::string("1\0", 2), ret)); + BOOST_CHECK(!ParseMoney("\0-1"s, ret)); + BOOST_CHECK(!ParseMoney("\0" "1"s, ret)); + BOOST_CHECK(!ParseMoney("1\0"s, ret)); } BOOST_AUTO_TEST_CASE(util_IsHex) @@ -1398,10 +1423,18 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32) BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647); BOOST_CHECK(ParseInt32("-2147483648", &n) && n == (-2147483647 - 1)); // (-2147483647 - 1) equals INT_MIN BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234); + BOOST_CHECK(ParseInt32("00000000000000001234", &n) && n == 1234); + BOOST_CHECK(ParseInt32("-00000000000000001234", &n) && n == -1234); + BOOST_CHECK(ParseInt32("00000000000000000000", &n) && n == 0); + BOOST_CHECK(ParseInt32("-00000000000000000000", &n) && n == 0); // Invalid values BOOST_CHECK(!ParseInt32("", &n)); BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside BOOST_CHECK(!ParseInt32("1 ", &n)); + BOOST_CHECK(!ParseInt32("++1", &n)); + BOOST_CHECK(!ParseInt32("+-1", &n)); + BOOST_CHECK(!ParseInt32("-+1", &n)); + BOOST_CHECK(!ParseInt32("--1", &n)); BOOST_CHECK(!ParseInt32("1a", &n)); BOOST_CHECK(!ParseInt32("aap", &n)); BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex @@ -1457,10 +1490,19 @@ BOOST_AUTO_TEST_CASE(test_ParseUInt32) BOOST_CHECK(ParseUInt32("2147483647", &n) && n == 2147483647); BOOST_CHECK(ParseUInt32("2147483648", &n) && n == (uint32_t)2147483648); BOOST_CHECK(ParseUInt32("4294967295", &n) && n == (uint32_t)4294967295); + BOOST_CHECK(ParseUInt32("+1234", &n) && n == 1234); + BOOST_CHECK(ParseUInt32("00000000000000001234", &n) && n == 1234); + BOOST_CHECK(ParseUInt32("00000000000000000000", &n) && n == 0); // Invalid values + BOOST_CHECK(!ParseUInt32("-00000000000000000000", &n)); BOOST_CHECK(!ParseUInt32("", &n)); BOOST_CHECK(!ParseUInt32(" 1", &n)); // no padding inside BOOST_CHECK(!ParseUInt32(" -1", &n)); + BOOST_CHECK(!ParseUInt32("++1", &n)); + BOOST_CHECK(!ParseUInt32("+-1", &n)); + BOOST_CHECK(!ParseUInt32("-+1", &n)); + BOOST_CHECK(!ParseUInt32("--1", &n)); + BOOST_CHECK(!ParseUInt32("-1", &n)); BOOST_CHECK(!ParseUInt32("1 ", &n)); BOOST_CHECK(!ParseUInt32("1a", &n)); BOOST_CHECK(!ParseUInt32("aap", &n)); @@ -1571,9 +1613,9 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion) std::vector<std::string> comments2; comments2.push_back(std::string("comment1")); comments2.push_back(SanitizeString(std::string("Comment2; .,_?@-; !\"#$%&'()*+/<=>[]\\^`{|}~"), SAFE_CHARS_UA_COMMENT)); // Semicolon is discouraged but not forbidden by BIP-0014 - BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/")); - BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/")); - BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; Comment2; .,_?@-; )/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:9.99.0/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:9.99.0(comment1)/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:9.99.0(comment1; Comment2; .,_?@-; )/")); } BOOST_AUTO_TEST_CASE(test_ParseFixedPoint) @@ -1818,7 +1860,7 @@ BOOST_AUTO_TEST_CASE(test_Capitalize) BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff"); } -static std::string SpanToStr(Span<const char>& span) +static std::string SpanToStr(const Span<const char>& span) { return std::string(span.begin(), span.end()); } @@ -1972,12 +2014,6 @@ struct Tracker copies = t.copies + 1; return *this; } - Tracker& operator=(Tracker&& t) noexcept - { - origin = t.origin; - copies = t.copies; - return *this; - } }; } diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 8e85b7df3e..ea17cb50f1 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -291,8 +291,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg) state, tx, &plTxnReplaced, - /* bypass_limits */ false, - /* nAbsurdFee */ 0)); + /* bypass_limits */ false)); } } diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index c8a375275f..92d8cf2e7d 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) return outp; }; - CChainState& c1 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool)); + CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(mempool)); c1.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23)); diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 36badafc4e..3d8570e27c 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -15,21 +15,22 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, ChainTestingSetup) //! Basic tests for ChainstateManager. //! //! First create a legacy (IBD) chainstate, then create a snapshot chainstate. BOOST_AUTO_TEST_CASE(chainstatemanager) { - ChainstateManager manager; - CTxMemPool mempool; + ChainstateManager& manager = *m_node.chainman; + CTxMemPool& mempool = *m_node.mempool; + std::vector<CChainState*> chainstates; const CChainParams& chainparams = Params(); // Create a legacy (IBD) chainstate. // - CChainState& c1 = *WITH_LOCK(::cs_main, return &manager.InitializeChainstate(mempool)); + CChainState& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); @@ -55,7 +56,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) // Create a snapshot-based chainstate. // - CChainState& c2 = *WITH_LOCK(::cs_main, return &manager.InitializeChainstate(mempool, GetRandHash())); + CChainState& c2 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(mempool, GetRandHash())); chainstates.push_back(&c2); c2.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); @@ -104,8 +105,9 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) //! Test rebalancing the caches associated with each chainstate. BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) { - ChainstateManager manager; - CTxMemPool mempool; + ChainstateManager& manager = *m_node.chainman; + CTxMemPool& mempool = *m_node.mempool; + size_t max_cache = 10000; manager.m_total_coinsdb_cache = max_cache; manager.m_total_coinstip_cache = max_cache; @@ -114,7 +116,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) // Create a legacy (IBD) chainstate. // - CChainState& c1 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool)); + CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); @@ -122,6 +124,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) { LOCK(::cs_main); c1.InitCoinsCache(1 << 23); + BOOST_REQUIRE(c1.LoadGenesisBlock(Params())); c1.CoinsTip().SetBestBlock(InsecureRand256()); manager.MaybeRebalanceCaches(); } @@ -131,7 +134,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) // Create a snapshot-based chainstate. // - CChainState& c2 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool, GetRandHash())); + CChainState& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(mempool, GetRandHash())); chainstates.push_back(&c2); c2.InitCoinsDB( /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false); @@ -139,6 +142,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) { LOCK(::cs_main); c2.InitCoinsCache(1 << 23); + BOOST_REQUIRE(c2.LoadGenesisBlock(Params())); c2.CoinsTip().SetBestBlock(InsecureRand256()); manager.MaybeRebalanceCaches(); } diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp index 3b961db52d..9e37f14921 100644 --- a/src/test/validation_tests.cpp +++ b/src/test/validation_tests.cpp @@ -1,14 +1,14 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> #include <net.h> +#include <signet.h> #include <validation.h> #include <test/util/setup_common.h> -#include <boost/signals2/signal.hpp> #include <boost/test/unit_test.hpp> BOOST_FIXTURE_TEST_SUITE(validation_tests, TestingSetup) @@ -39,7 +39,7 @@ static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval) BOOST_AUTO_TEST_CASE(block_subsidy_test) { - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); TestBlockSubsidyHalvings(chainParams->GetConsensus()); // As in main TestBlockSubsidyHalvings(150); // As in regtest TestBlockSubsidyHalvings(1000); // Just another interval @@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(block_subsidy_test) BOOST_AUTO_TEST_CASE(subsidy_limit_test) { - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); CAmount nSum = 0; for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) { CAmount nSubsidy = GetBlockSubsidy(nHeight, chainParams->GetConsensus()); @@ -58,20 +58,65 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) BOOST_CHECK_EQUAL(nSum, CAmount{2099999997690000}); } -static bool ReturnFalse() { return false; } -static bool ReturnTrue() { return true; } - -BOOST_AUTO_TEST_CASE(test_combiner_all) +BOOST_AUTO_TEST_CASE(signet_parse_tests) { - boost::signals2::signal<bool (), CombinerAll> Test; - BOOST_CHECK(Test()); - Test.connect(&ReturnFalse); - BOOST_CHECK(!Test()); - Test.connect(&ReturnTrue); - BOOST_CHECK(!Test()); - Test.disconnect(&ReturnFalse); - BOOST_CHECK(Test()); - Test.disconnect(&ReturnTrue); - BOOST_CHECK(Test()); + ArgsManager signet_argsman; + signet_argsman.ForceSetArg("-signetchallenge", "51"); // set challenge to OP_TRUE + const auto signet_params = CreateChainParams(signet_argsman, CBaseChainParams::SIGNET); + CBlock block; + BOOST_CHECK(signet_params->GetConsensus().signet_challenge == std::vector<uint8_t>{OP_TRUE}); + CScript challenge{OP_TRUE}; + + // empty block is invalid + BOOST_CHECK(!SignetTxs::Create(block, challenge)); + BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus())); + + // no witness commitment + CMutableTransaction cb; + cb.vout.emplace_back(0, CScript{}); + block.vtx.push_back(MakeTransactionRef(cb)); + block.vtx.push_back(MakeTransactionRef(cb)); // Add dummy tx to exercise merkle root code + BOOST_CHECK(!SignetTxs::Create(block, challenge)); + BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus())); + + // no header is treated valid + std::vector<uint8_t> witness_commitment_section_141{0xaa, 0x21, 0xa9, 0xed}; + for (int i = 0; i < 32; ++i) { + witness_commitment_section_141.push_back(0xff); + } + cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141; + block.vtx.at(0) = MakeTransactionRef(cb); + BOOST_CHECK(SignetTxs::Create(block, challenge)); + BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus())); + + // no data after header, valid + std::vector<uint8_t> witness_commitment_section_325{0xec, 0xc7, 0xda, 0xa2}; + cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325; + block.vtx.at(0) = MakeTransactionRef(cb); + BOOST_CHECK(SignetTxs::Create(block, challenge)); + BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus())); + + // Premature end of data, invalid + witness_commitment_section_325.push_back(0x01); + witness_commitment_section_325.push_back(0x51); + cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325; + block.vtx.at(0) = MakeTransactionRef(cb); + BOOST_CHECK(!SignetTxs::Create(block, challenge)); + BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus())); + + // has data, valid + witness_commitment_section_325.push_back(0x00); + cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325; + block.vtx.at(0) = MakeTransactionRef(cb); + BOOST_CHECK(SignetTxs::Create(block, challenge)); + BOOST_CHECK(CheckSignetBlockSolution(block, signet_params->GetConsensus())); + + // Extraneous data, invalid + witness_commitment_section_325.push_back(0x00); + cb.vout.at(0).scriptPubKey = CScript{} << OP_RETURN << witness_commitment_section_141 << witness_commitment_section_325; + block.vtx.at(0) = MakeTransactionRef(cb); + BOOST_CHECK(!SignetTxs::Create(block, challenge)); + BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus())); } + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index 11c6bdad91..50444f7bbe 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -223,7 +223,7 @@ BOOST_AUTO_TEST_CASE(versionbits_test) } // Sanity checks of version bit deployments - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); const Consensus::Params &mainnetParams = chainParams->GetConsensus(); for (int i=0; i<(int) Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { uint32_t bitmask = VersionBitsMask(mainnetParams, static_cast<Consensus::DeploymentPos>(i)); @@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) { // Check that ComputeBlockVersion will set the appropriate bit correctly // on mainnet. - const auto chainParams = CreateChainParams(CBaseChainParams::MAIN); + const auto chainParams = CreateChainParams(*m_node.args, CBaseChainParams::MAIN); const Consensus::Params &mainnetParams = chainParams->GetConsensus(); // Use the TESTDUMMY deployment for testing purposes. diff --git a/src/threadsafety.h b/src/threadsafety.h index 52bf83b676..28b6177927 100644 --- a/src/threadsafety.h +++ b/src/threadsafety.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/timedata.cpp b/src/timedata.cpp index 6b3a79017b..354092752d 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -36,11 +36,6 @@ int64_t GetAdjustedTime() return GetTime() + GetTimeOffset(); } -static int64_t abs64(int64_t n) -{ - return (n >= 0 ? n : -n); -} - #define BITCOIN_TIMEDATA_MAX_SAMPLES 200 void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) @@ -79,7 +74,8 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) int64_t nMedian = vTimeOffsets.median(); std::vector<int64_t> vSorted = vTimeOffsets.sorted(); // Only let other nodes change our time by so much - if (abs64(nMedian) <= std::max<int64_t>(0, gArgs.GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT))) { + int64_t max_adjustment = std::max<int64_t>(0, gArgs.GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT)); + if (nMedian >= -max_adjustment && nMedian <= max_adjustment) { nTimeOffset = nMedian; } else { nTimeOffset = 0; @@ -89,7 +85,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) // If nobody has a time different than ours but within 5 minutes of ours, give a warning bool fMatch = false; for (const int64_t nOffset : vSorted) { - if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true; + if (nOffset != 0 && nOffset > -5 * 60 && nOffset < 5 * 60) fMatch = true; } if (!fMatch) { diff --git a/src/tinyformat.h b/src/tinyformat.h index be63f2d5d8..bc893ccda5 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -514,7 +514,7 @@ class FormatArg { } template<typename T> - FormatArg(const T& value) + explicit FormatArg(const T& value) : m_value(static_cast<const void*>(&value)), m_formatImpl(&formatImpl<T>), m_toIntImpl(&toIntImpl<T>) @@ -970,7 +970,7 @@ class FormatListN : public FormatList public: #ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES template<typename... Args> - FormatListN(const Args&... args) + explicit FormatListN(const Args&... args) : FormatList(&m_formatterStore[0], N), m_formatterStore { FormatArg(args)... } { static_assert(sizeof...(args) == N, "Number of args must be N"); } diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 5d56d1ff89..908ad35e1b 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -1,20 +1,25 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <chainparams.h> #include <torcontrol.h> -#include <util/strencodings.h> -#include <netbase.h> + +#include <chainparams.h> +#include <chainparamsbase.h> +#include <compat.h> +#include <crypto/hmac_sha256.h> #include <net.h> +#include <netaddress.h> +#include <netbase.h> +#include <util/strencodings.h> #include <util/system.h> -#include <crypto/hmac_sha256.h> -#include <vector> #include <deque> +#include <functional> #include <set> #include <stdlib.h> +#include <vector> #include <boost/signals2/signal.hpp> #include <boost/algorithm/string/split.hpp> @@ -81,12 +86,12 @@ public: /** * Connect to a Tor control port. - * target is address of the form host:port. + * tor_control_center is address of the form host:port. * connected is the handler that is called when connection is successfully established. * disconnected is a handler that is called when the connection is broken. * Return true on success. */ - bool Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected); + bool Connect(const std::string& tor_control_center, const ConnectionCB& connected, const ConnectionCB& disconnected); /** * Disconnect from Tor control port. @@ -193,16 +198,16 @@ void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ct } } -bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& _connected, const ConnectionCB& _disconnected) +bool TorControlConnection::Connect(const std::string& tor_control_center, const ConnectionCB& _connected, const ConnectionCB& _disconnected) { if (b_conn) Disconnect(); - // Parse target address:port + // Parse tor_control_center address:port struct sockaddr_storage connect_to_addr; int connect_to_addrlen = sizeof(connect_to_addr); - if (evutil_parse_sockaddr_port(target.c_str(), + if (evutil_parse_sockaddr_port(tor_control_center.c_str(), (struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) { - LogPrintf("tor: Error parsing socket address %s\n", target); + LogPrintf("tor: Error parsing socket address %s\n", tor_control_center); return false; } @@ -215,9 +220,9 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB this->connected = _connected; this->disconnected = _disconnected; - // Finally, connect to target + // Finally, connect to tor_control_center if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) { - LogPrintf("tor: Error connecting to address %s\n", target); + LogPrintf("tor: Error connecting to address %s\n", tor_control_center); return false; } return true; @@ -410,7 +415,7 @@ static bool WriteBinaryFile(const fs::path &filename, const std::string &data) class TorController { public: - TorController(struct event_base* base, const std::string& target); + TorController(struct event_base* base, const std::string& tor_control_center, const CService& target); ~TorController(); /** Get name of file to store private key in */ @@ -420,7 +425,7 @@ public: void Reconnect(); private: struct event_base* base; - std::string target; + const std::string m_tor_control_center; TorControlConnection conn; std::string private_key; std::string service_id; @@ -428,6 +433,7 @@ private: struct event *reconnect_ev; float reconnect_timeout; CService service; + const CService m_target; /** Cookie for SAFECOOKIE auth */ std::vector<uint8_t> cookie; /** ClientNonce for SAFECOOKIE auth */ @@ -450,18 +456,19 @@ private: static void reconnect_cb(evutil_socket_t fd, short what, void *arg); }; -TorController::TorController(struct event_base* _base, const std::string& _target): +TorController::TorController(struct event_base* _base, const std::string& tor_control_center, const CService& target): base(_base), - target(_target), conn(base), reconnect(true), reconnect_ev(0), - reconnect_timeout(RECONNECT_TIMEOUT_START) + m_tor_control_center(tor_control_center), conn(base), reconnect(true), reconnect_ev(0), + reconnect_timeout(RECONNECT_TIMEOUT_START), + m_target(target) { reconnect_ev = event_new(base, -1, 0, reconnect_cb, this); if (!reconnect_ev) LogPrintf("tor: Failed to create event for reconnection: out of memory?\n"); // Start connection attempts immediately - if (!conn.Connect(_target, std::bind(&TorController::connected_cb, this, std::placeholders::_1), + if (!conn.Connect(m_tor_control_center, std::bind(&TorController::connected_cb, this, std::placeholders::_1), std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) { - LogPrintf("tor: Initiating connection to Tor control port %s failed\n", _target); + LogPrintf("tor: Initiating connection to Tor control port %s failed\n", m_tor_control_center); } // Read service private key if cached std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile()); @@ -532,11 +539,12 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& } // Finally - now create the service - if (private_key.empty()) // No private key, generate one - private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214 + if (private_key.empty()) { // No private key, generate one + private_key = "NEW:ED25519-V3"; // Explicitly request key type - see issue #9214 + } // Request onion service, redirect port. // Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports. - _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, Params().GetDefaultPort(), GetListenPort()), + _conn.Command(strprintf("ADD_ONION %s Port=%i,%s", private_key, Params().GetDefaultPort(), m_target.ToStringIPPort()), std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2)); } else { LogPrintf("tor: Authentication failed\n"); @@ -696,7 +704,7 @@ void TorController::disconnected_cb(TorControlConnection& _conn) if (!reconnect) return; - LogPrint(BCLog::TOR, "tor: Not connected to Tor control port %s, trying to reconnect\n", target); + LogPrint(BCLog::TOR, "tor: Not connected to Tor control port %s, trying to reconnect\n", m_tor_control_center); // Single-shot timer for reconnect. Use exponential backoff. struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0)); @@ -710,15 +718,15 @@ void TorController::Reconnect() /* Try to reconnect and reestablish if we get booted - for example, Tor * may be restarting. */ - if (!conn.Connect(target, std::bind(&TorController::connected_cb, this, std::placeholders::_1), + if (!conn.Connect(m_tor_control_center, std::bind(&TorController::connected_cb, this, std::placeholders::_1), std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) { - LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target); + LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", m_tor_control_center); } } fs::path TorController::GetPrivateKeyFile() { - return GetDataDir() / "onion_private_key"; + return GetDataDir() / "onion_v3_private_key"; } void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) @@ -731,14 +739,14 @@ void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) static struct event_base *gBase; static std::thread torControlThread; -static void TorControlThread() +static void TorControlThread(CService onion_service_target) { - TorController ctrl(gBase, gArgs.GetArg("-torcontrol", DEFAULT_TOR_CONTROL)); + TorController ctrl(gBase, gArgs.GetArg("-torcontrol", DEFAULT_TOR_CONTROL), onion_service_target); event_base_dispatch(gBase); } -void StartTorControl() +void StartTorControl(CService onion_service_target) { assert(!gBase); #ifdef WIN32 @@ -752,7 +760,9 @@ void StartTorControl() return; } - torControlThread = std::thread(std::bind(&TraceThread<void (*)()>, "torcontrol", &TorControlThread)); + torControlThread = std::thread(&TraceThread<std::function<void()>>, "torcontrol", [onion_service_target] { + TorControlThread(onion_service_target); + }); } void InterruptTorControl() @@ -773,3 +783,10 @@ void StopTorControl() gBase = nullptr; } } + +CService DefaultOnionServiceTarget() +{ + struct in_addr onion_service_target; + onion_service_target.s_addr = htonl(INADDR_LOOPBACK); + return {onion_service_target, BaseParams().OnionServiceTargetPort()}; +} diff --git a/src/torcontrol.h b/src/torcontrol.h index 474a4d87d9..00f19db6ae 100644 --- a/src/torcontrol.h +++ b/src/torcontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,12 +8,17 @@ #ifndef BITCOIN_TORCONTROL_H #define BITCOIN_TORCONTROL_H +#include <string> + +class CService; extern const std::string DEFAULT_TOR_CONTROL; static const bool DEFAULT_LISTEN_ONION = true; -void StartTorControl(); +void StartTorControl(CService onion_service_target); void InterruptTorControl(); void StopTorControl(); +CService DefaultOnionServiceTarget(); + #endif /* BITCOIN_TORCONTROL_H */ diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 0c2b731967..470e665844 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -331,15 +331,10 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, assert(int(nSigOpCostWithAncestors) >= 0); } -CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) - : nTransactionsUpdated(0), minerPolicyEstimator(estimator), m_epoch(0), m_has_epoch_guard(false) +CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator, int check_ratio) + : m_check_ratio(check_ratio), minerPolicyEstimator(estimator) { _clear(); //lock free clear - - // Sanity checks off by default for performance, because otherwise - // accepting transactions becomes O(N^2) where N is the number - // of transactions in the pool - nCheckFrequency = 0; } bool CTxMemPool::isSpent(const COutPoint& outpoint) const @@ -523,7 +518,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem if (it2 != mapTx.end()) continue; const Coin &coin = pcoins->AccessCoin(txin.prevout); - if (nCheckFrequency != 0) assert(!coin.IsSpent()); + if (m_check_ratio != 0) assert(!coin.IsSpent()); if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) { txToRemove.insert(it); break; @@ -619,13 +614,12 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m void CTxMemPool::check(const CCoinsViewCache *pcoins) const { - LOCK(cs); - if (nCheckFrequency == 0) - return; + if (m_check_ratio == 0) return; - if (GetRand(std::numeric_limits<uint32_t>::max()) >= nCheckFrequency) - return; + if (GetRand(m_check_ratio) >= 1) return; + AssertLockHeld(::cs_main); + LOCK(cs); LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); uint64_t checkTotal = 0; @@ -1134,5 +1128,3 @@ CTxMemPool::EpochGuard::~EpochGuard() ++pool.m_epoch; pool.m_has_epoch_guard = false; } - -SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {} diff --git a/src/txmempool.h b/src/txmempool.h index f513f14af6..0a9cd81ff5 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -15,13 +15,13 @@ #include <amount.h> #include <coins.h> -#include <crypto/siphash.h> #include <indirectmap.h> #include <optional.h> #include <policy/feerate.h> #include <primitives/transaction.h> #include <sync.h> #include <random.h> +#include <util/hasher.h> #include <boost/multi_index_container.hpp> #include <boost/multi_index/hashed_index.hpp> @@ -398,20 +398,6 @@ enum class MemPoolRemovalReason { REPLACED, //!< Removed for replacement }; -class SaltedTxidHasher -{ -private: - /** Salt */ - const uint64_t k0, k1; - -public: - SaltedTxidHasher(); - - size_t operator()(const uint256& txid) const { - return SipHashUint256(k0, k1, txid); - } -}; - /** * CTxMemPool stores valid-according-to-the-current-best-chain transactions * that may be included in the next block. @@ -488,8 +474,8 @@ public: class CTxMemPool { private: - uint32_t nCheckFrequency GUARDED_BY(cs); //!< Value n means that n times in 2^32 we check. - std::atomic<unsigned int> nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation + const int m_check_ratio; //!< Value n means that 1 times in n we check. + std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation CBlockPolicyEstimator* minerPolicyEstimator; uint64_t totalTxSize; //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141. @@ -498,8 +484,8 @@ private: mutable int64_t lastRollingFeeUpdate; mutable bool blockSinceLastRollingFeeBump; mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially - mutable uint64_t m_epoch; - mutable bool m_has_epoch_guard; + mutable uint64_t m_epoch{0}; + mutable bool m_has_epoch_guard{false}; // In-memory counter for external mempool tracking purposes. // This number is incremented once every time a transaction @@ -601,8 +587,14 @@ public: std::map<uint256, CAmount> mapDeltas; /** Create a new CTxMemPool. + * Sanity checks will be off by default for performance, because otherwise + * accepting transactions becomes O(N^2) where N is the number of transactions + * in the pool. + * + * @param[in] estimator is used to estimate appropriate transaction fees. + * @param[in] check_ratio is the ratio used to determine how often sanity checks will run. */ - explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr); + explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr, int check_ratio = 0); /** * If sanity-checking is turned on, check makes sure the pool is @@ -610,8 +602,7 @@ public: * all inputs are in the mapNextTx array). If sanity-checking is turned off, * check does nothing. */ - void check(const CCoinsViewCache *pcoins) const; - void setSanityCheck(double dFrequency = 1.0) { LOCK(cs); nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); } + void check(const CCoinsViewCache *pcoins) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); // addUnchecked must updated state for all ancestors of a given transaction, // to track size/count of descendant transactions. First version of @@ -850,7 +841,7 @@ public: class EpochGuard { const CTxMemPool& pool; public: - EpochGuard(const CTxMemPool& in); + explicit EpochGuard(const CTxMemPool& in); ~EpochGuard(); }; // N.B. GetFreshEpoch modifies mutable state via the EpochGuard construction diff --git a/src/txrequest.cpp b/src/txrequest.cpp new file mode 100644 index 0000000000..e54c073328 --- /dev/null +++ b/src/txrequest.cpp @@ -0,0 +1,756 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <txrequest.h> + +#include <crypto/siphash.h> +#include <net.h> +#include <primitives/transaction.h> +#include <random.h> +#include <uint256.h> +#include <util/memory.h> + +#include <boost/multi_index_container.hpp> +#include <boost/multi_index/ordered_index.hpp> + +#include <chrono> +#include <unordered_map> +#include <utility> + +#include <assert.h> + +namespace { + +/** The various states a (txhash,peer) pair can be in. + * + * Note that CANDIDATE is split up into 3 substates (DELAYED, BEST, READY), allowing more efficient implementation. + * Also note that the sorting order of ByTxHashView relies on the specific order of values in this enum. + * + * Expected behaviour is: + * - When first announced by a peer, the state is CANDIDATE_DELAYED until reqtime is reached. + * - Announcements that have reached their reqtime but not been requested will be either CANDIDATE_READY or + * CANDIDATE_BEST. Neither of those has an expiration time; they remain in that state until they're requested or + * no longer needed. CANDIDATE_READY announcements are promoted to CANDIDATE_BEST when they're the best one left. + * - When requested, an announcement will be in state REQUESTED until expiry is reached. + * - If expiry is reached, or the peer replies to the request (either with NOTFOUND or the tx), the state becomes + * COMPLETED. + */ +enum class State : uint8_t { + /** A CANDIDATE announcement whose reqtime is in the future. */ + CANDIDATE_DELAYED, + /** A CANDIDATE announcement that's not CANDIDATE_DELAYED or CANDIDATE_BEST. */ + CANDIDATE_READY, + /** The best CANDIDATE for a given txhash; only if there is no REQUESTED announcement already for that txhash. + * The CANDIDATE_BEST is the highest-priority announcement among all CANDIDATE_READY (and _BEST) ones for that + * txhash. */ + CANDIDATE_BEST, + /** A REQUESTED announcement. */ + REQUESTED, + /** A COMPLETED announcement. */ + COMPLETED, +}; + +//! Type alias for sequence numbers. +using SequenceNumber = uint64_t; + +/** An announcement. This is the data we track for each txid or wtxid that is announced to us by each peer. */ +struct Announcement { + /** Txid or wtxid that was announced. */ + const uint256 m_txhash; + /** For CANDIDATE_{DELAYED,BEST,READY} the reqtime; for REQUESTED the expiry. */ + std::chrono::microseconds m_time; + /** What peer the request was from. */ + const NodeId m_peer; + /** What sequence number this announcement has. */ + const SequenceNumber m_sequence : 59; + /** Whether the request is preferred. */ + const bool m_preferred : 1; + /** Whether this is a wtxid request. */ + const bool m_is_wtxid : 1; + + /** What state this announcement is in. + * This is a uint8_t instead of a State to silence a GCC warning in versions prior to 8.4 and 9.3. + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414 */ + uint8_t m_state : 3; + + /** Convert m_state to a State enum. */ + State GetState() const { return static_cast<State>(m_state); } + + /** Convert a State enum to a uint8_t and store it in m_state. */ + void SetState(State state) { m_state = static_cast<uint8_t>(state); } + + /** Whether this announcement is selected. There can be at most 1 selected peer per txhash. */ + bool IsSelected() const + { + return GetState() == State::CANDIDATE_BEST || GetState() == State::REQUESTED; + } + + /** Whether this announcement is waiting for a certain time to pass. */ + bool IsWaiting() const + { + return GetState() == State::REQUESTED || GetState() == State::CANDIDATE_DELAYED; + } + + /** Whether this announcement can feasibly be selected if the current IsSelected() one disappears. */ + bool IsSelectable() const + { + return GetState() == State::CANDIDATE_READY || GetState() == State::CANDIDATE_BEST; + } + + /** Construct a new announcement from scratch, initially in CANDIDATE_DELAYED state. */ + Announcement(const GenTxid& gtxid, NodeId peer, bool preferred, std::chrono::microseconds reqtime, + SequenceNumber sequence) : + m_txhash(gtxid.GetHash()), m_time(reqtime), m_peer(peer), m_sequence(sequence), m_preferred(preferred), + m_is_wtxid(gtxid.IsWtxid()), m_state(static_cast<uint8_t>(State::CANDIDATE_DELAYED)) {} +}; + +//! Type alias for priorities. +using Priority = uint64_t; + +/** A functor with embedded salt that computes priority of an announcement. + * + * Higher priorities are selected first. + */ +class PriorityComputer { + const uint64_t m_k0, m_k1; +public: + explicit PriorityComputer(bool deterministic) : + m_k0{deterministic ? 0 : GetRand(0xFFFFFFFFFFFFFFFF)}, + m_k1{deterministic ? 0 : GetRand(0xFFFFFFFFFFFFFFFF)} {} + + Priority operator()(const uint256& txhash, NodeId peer, bool preferred) const + { + uint64_t low_bits = CSipHasher(m_k0, m_k1).Write(txhash.begin(), txhash.size()).Write(peer).Finalize() >> 1; + return low_bits | uint64_t{preferred} << 63; + } + + Priority operator()(const Announcement& ann) const + { + return operator()(ann.m_txhash, ann.m_peer, ann.m_preferred); + } +}; + +// Definitions for the 3 indexes used in the main data structure. +// +// Each index has a By* type to identify it, a By*View data type to represent the view of announcement it is sorted +// by, and an By*ViewExtractor type to convert an announcement into the By*View type. +// See https://www.boost.org/doc/libs/1_58_0/libs/multi_index/doc/reference/key_extraction.html#key_extractors +// for more information about the key extraction concept. + +// The ByPeer index is sorted by (peer, state == CANDIDATE_BEST, txhash) +// +// Uses: +// * Looking up existing announcements by peer/txhash, by checking both (peer, false, txhash) and +// (peer, true, txhash). +// * Finding all CANDIDATE_BEST announcements for a given peer in GetRequestable. +struct ByPeer {}; +using ByPeerView = std::tuple<NodeId, bool, const uint256&>; +struct ByPeerViewExtractor +{ + using result_type = ByPeerView; + result_type operator()(const Announcement& ann) const + { + return ByPeerView{ann.m_peer, ann.GetState() == State::CANDIDATE_BEST, ann.m_txhash}; + } +}; + +// The ByTxHash index is sorted by (txhash, state, priority). +// +// Note: priority == 0 whenever state != CANDIDATE_READY. +// +// Uses: +// * Deleting all announcements with a given txhash in ForgetTxHash. +// * Finding the best CANDIDATE_READY to convert to CANDIDATE_BEST, when no other CANDIDATE_READY or REQUESTED +// announcement exists for that txhash. +// * Determining when no more non-COMPLETED announcements for a given txhash exist, so the COMPLETED ones can be +// deleted. +struct ByTxHash {}; +using ByTxHashView = std::tuple<const uint256&, State, Priority>; +class ByTxHashViewExtractor { + const PriorityComputer& m_computer; +public: + explicit ByTxHashViewExtractor(const PriorityComputer& computer) : m_computer(computer) {} + using result_type = ByTxHashView; + result_type operator()(const Announcement& ann) const + { + const Priority prio = (ann.GetState() == State::CANDIDATE_READY) ? m_computer(ann) : 0; + return ByTxHashView{ann.m_txhash, ann.GetState(), prio}; + } +}; + +enum class WaitState { + //! Used for announcements that need efficient testing of "is their timestamp in the future?". + FUTURE_EVENT, + //! Used for announcements whose timestamp is not relevant. + NO_EVENT, + //! Used for announcements that need efficient testing of "is their timestamp in the past?". + PAST_EVENT, +}; + +WaitState GetWaitState(const Announcement& ann) +{ + if (ann.IsWaiting()) return WaitState::FUTURE_EVENT; + if (ann.IsSelectable()) return WaitState::PAST_EVENT; + return WaitState::NO_EVENT; +} + +// The ByTime index is sorted by (wait_state, time). +// +// All announcements with a timestamp in the future can be found by iterating the index forward from the beginning. +// All announcements with a timestamp in the past can be found by iterating the index backwards from the end. +// +// Uses: +// * Finding CANDIDATE_DELAYED announcements whose reqtime has passed, and REQUESTED announcements whose expiry has +// passed. +// * Finding CANDIDATE_READY/BEST announcements whose reqtime is in the future (when the clock time went backwards). +struct ByTime {}; +using ByTimeView = std::pair<WaitState, std::chrono::microseconds>; +struct ByTimeViewExtractor +{ + using result_type = ByTimeView; + result_type operator()(const Announcement& ann) const + { + return ByTimeView{GetWaitState(ann), ann.m_time}; + } +}; + +/** Data type for the main data structure (Announcement objects with ByPeer/ByTxHash/ByTime indexes). */ +using Index = boost::multi_index_container< + Announcement, + boost::multi_index::indexed_by< + boost::multi_index::ordered_unique<boost::multi_index::tag<ByPeer>, ByPeerViewExtractor>, + boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByTxHash>, ByTxHashViewExtractor>, + boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByTime>, ByTimeViewExtractor> + > +>; + +/** Helper type to simplify syntax of iterator types. */ +template<typename Tag> +using Iter = typename Index::index<Tag>::type::iterator; + +/** Per-peer statistics object. */ +struct PeerInfo { + size_t m_total = 0; //!< Total number of announcements for this peer. + size_t m_completed = 0; //!< Number of COMPLETED announcements for this peer. + size_t m_requested = 0; //!< Number of REQUESTED announcements for this peer. +}; + +/** Per-txhash statistics object. Only used for sanity checking. */ +struct TxHashInfo +{ + //! Number of CANDIDATE_DELAYED announcements for this txhash. + size_t m_candidate_delayed = 0; + //! Number of CANDIDATE_READY announcements for this txhash. + size_t m_candidate_ready = 0; + //! Number of CANDIDATE_BEST announcements for this txhash (at most one). + size_t m_candidate_best = 0; + //! Number of REQUESTED announcements for this txhash (at most one; mutually exclusive with CANDIDATE_BEST). + size_t m_requested = 0; + //! The priority of the CANDIDATE_BEST announcement if one exists, or max() otherwise. + Priority m_priority_candidate_best = std::numeric_limits<Priority>::max(); + //! The highest priority of all CANDIDATE_READY announcements (or min() if none exist). + Priority m_priority_best_candidate_ready = std::numeric_limits<Priority>::min(); + //! All peers we have an announcement for this txhash for. + std::vector<NodeId> m_peers; +}; + +/** Compare two PeerInfo objects. Only used for sanity checking. */ +bool operator==(const PeerInfo& a, const PeerInfo& b) +{ + return std::tie(a.m_total, a.m_completed, a.m_requested) == + std::tie(b.m_total, b.m_completed, b.m_requested); +}; + +/** (Re)compute the PeerInfo map from the index. Only used for sanity checking. */ +std::unordered_map<NodeId, PeerInfo> RecomputePeerInfo(const Index& index) +{ + std::unordered_map<NodeId, PeerInfo> ret; + for (const Announcement& ann : index) { + PeerInfo& info = ret[ann.m_peer]; + ++info.m_total; + info.m_requested += (ann.GetState() == State::REQUESTED); + info.m_completed += (ann.GetState() == State::COMPLETED); + } + return ret; +} + +/** Compute the TxHashInfo map. Only used for sanity checking. */ +std::map<uint256, TxHashInfo> ComputeTxHashInfo(const Index& index, const PriorityComputer& computer) +{ + std::map<uint256, TxHashInfo> ret; + for (const Announcement& ann : index) { + TxHashInfo& info = ret[ann.m_txhash]; + // Classify how many announcements of each state we have for this txhash. + info.m_candidate_delayed += (ann.GetState() == State::CANDIDATE_DELAYED); + info.m_candidate_ready += (ann.GetState() == State::CANDIDATE_READY); + info.m_candidate_best += (ann.GetState() == State::CANDIDATE_BEST); + info.m_requested += (ann.GetState() == State::REQUESTED); + // And track the priority of the best CANDIDATE_READY/CANDIDATE_BEST announcements. + if (ann.GetState() == State::CANDIDATE_BEST) { + info.m_priority_candidate_best = computer(ann); + } + if (ann.GetState() == State::CANDIDATE_READY) { + info.m_priority_best_candidate_ready = std::max(info.m_priority_best_candidate_ready, computer(ann)); + } + // Also keep track of which peers this txhash has an announcement for (so we can detect duplicates). + info.m_peers.push_back(ann.m_peer); + } + return ret; +} + +GenTxid ToGenTxid(const Announcement& ann) +{ + return {ann.m_is_wtxid, ann.m_txhash}; +} + +} // namespace + +/** Actual implementation for TxRequestTracker's data structure. */ +class TxRequestTracker::Impl { + //! The current sequence number. Increases for every announcement. This is used to sort txhashes returned by + //! GetRequestable in announcement order. + SequenceNumber m_current_sequence{0}; + + //! This tracker's priority computer. + const PriorityComputer m_computer; + + //! This tracker's main data structure. See SanityCheck() for the invariants that apply to it. + Index m_index; + + //! Map with this tracker's per-peer statistics. + std::unordered_map<NodeId, PeerInfo> m_peerinfo; + +public: + void SanityCheck() const + { + // Recompute m_peerdata from m_index. This verifies the data in it as it should just be caching statistics + // on m_index. It also verifies the invariant that no PeerInfo announcements with m_total==0 exist. + assert(m_peerinfo == RecomputePeerInfo(m_index)); + + // Calculate per-txhash statistics from m_index, and validate invariants. + for (auto& item : ComputeTxHashInfo(m_index, m_computer)) { + TxHashInfo& info = item.second; + + // Cannot have only COMPLETED peer (txhash should have been forgotten already) + assert(info.m_candidate_delayed + info.m_candidate_ready + info.m_candidate_best + info.m_requested > 0); + + // Can have at most 1 CANDIDATE_BEST/REQUESTED peer + assert(info.m_candidate_best + info.m_requested <= 1); + + // If there are any CANDIDATE_READY announcements, there must be exactly one CANDIDATE_BEST or REQUESTED + // announcement. + if (info.m_candidate_ready > 0) { + assert(info.m_candidate_best + info.m_requested == 1); + } + + // If there is both a CANDIDATE_READY and a CANDIDATE_BEST announcement, the CANDIDATE_BEST one must be + // at least as good (equal or higher priority) as the best CANDIDATE_READY. + if (info.m_candidate_ready && info.m_candidate_best) { + assert(info.m_priority_candidate_best >= info.m_priority_best_candidate_ready); + } + + // No txhash can have been announced by the same peer twice. + std::sort(info.m_peers.begin(), info.m_peers.end()); + assert(std::adjacent_find(info.m_peers.begin(), info.m_peers.end()) == info.m_peers.end()); + } + } + + void PostGetRequestableSanityCheck(std::chrono::microseconds now) const + { + for (const Announcement& ann : m_index) { + if (ann.IsWaiting()) { + // REQUESTED and CANDIDATE_DELAYED must have a time in the future (they should have been converted + // to COMPLETED/CANDIDATE_READY respectively). + assert(ann.m_time > now); + } else if (ann.IsSelectable()) { + // CANDIDATE_READY and CANDIDATE_BEST cannot have a time in the future (they should have remained + // CANDIDATE_DELAYED, or should have been converted back to it if time went backwards). + assert(ann.m_time <= now); + } + } + } + +private: + //! Wrapper around Index::...::erase that keeps m_peerinfo up to date. + template<typename Tag> + Iter<Tag> Erase(Iter<Tag> it) + { + auto peerit = m_peerinfo.find(it->m_peer); + peerit->second.m_completed -= it->GetState() == State::COMPLETED; + peerit->second.m_requested -= it->GetState() == State::REQUESTED; + if (--peerit->second.m_total == 0) m_peerinfo.erase(peerit); + return m_index.get<Tag>().erase(it); + } + + //! Wrapper around Index::...::modify that keeps m_peerinfo up to date. + template<typename Tag, typename Modifier> + void Modify(Iter<Tag> it, Modifier modifier) + { + auto peerit = m_peerinfo.find(it->m_peer); + peerit->second.m_completed -= it->GetState() == State::COMPLETED; + peerit->second.m_requested -= it->GetState() == State::REQUESTED; + m_index.get<Tag>().modify(it, std::move(modifier)); + peerit->second.m_completed += it->GetState() == State::COMPLETED; + peerit->second.m_requested += it->GetState() == State::REQUESTED; + } + + //! Convert a CANDIDATE_DELAYED announcement into a CANDIDATE_READY. If this makes it the new best + //! CANDIDATE_READY (and no REQUESTED exists) and better than the CANDIDATE_BEST (if any), it becomes the new + //! CANDIDATE_BEST. + void PromoteCandidateReady(Iter<ByTxHash> it) + { + assert(it != m_index.get<ByTxHash>().end()); + assert(it->GetState() == State::CANDIDATE_DELAYED); + // Convert CANDIDATE_DELAYED to CANDIDATE_READY first. + Modify<ByTxHash>(it, [](Announcement& ann){ ann.SetState(State::CANDIDATE_READY); }); + // The following code relies on the fact that the ByTxHash is sorted by txhash, and then by state (first + // _DELAYED, then _READY, then _BEST/REQUESTED). Within the _READY announcements, the best one (highest + // priority) comes last. Thus, if an existing _BEST exists for the same txhash that this announcement may + // be preferred over, it must immediately follow the newly created _READY. + auto it_next = std::next(it); + if (it_next == m_index.get<ByTxHash>().end() || it_next->m_txhash != it->m_txhash || + it_next->GetState() == State::COMPLETED) { + // This is the new best CANDIDATE_READY, and there is no IsSelected() announcement for this txhash + // already. + Modify<ByTxHash>(it, [](Announcement& ann){ ann.SetState(State::CANDIDATE_BEST); }); + } else if (it_next->GetState() == State::CANDIDATE_BEST) { + Priority priority_old = m_computer(*it_next); + Priority priority_new = m_computer(*it); + if (priority_new > priority_old) { + // There is a CANDIDATE_BEST announcement already, but this one is better. + Modify<ByTxHash>(it_next, [](Announcement& ann){ ann.SetState(State::CANDIDATE_READY); }); + Modify<ByTxHash>(it, [](Announcement& ann){ ann.SetState(State::CANDIDATE_BEST); }); + } + } + } + + //! Change the state of an announcement to something non-IsSelected(). If it was IsSelected(), the next best + //! announcement will be marked CANDIDATE_BEST. + void ChangeAndReselect(Iter<ByTxHash> it, State new_state) + { + assert(new_state == State::COMPLETED || new_state == State::CANDIDATE_DELAYED); + assert(it != m_index.get<ByTxHash>().end()); + if (it->IsSelected() && it != m_index.get<ByTxHash>().begin()) { + auto it_prev = std::prev(it); + // The next best CANDIDATE_READY, if any, immediately precedes the REQUESTED or CANDIDATE_BEST + // announcement in the ByTxHash index. + if (it_prev->m_txhash == it->m_txhash && it_prev->GetState() == State::CANDIDATE_READY) { + // If one such CANDIDATE_READY exists (for this txhash), convert it to CANDIDATE_BEST. + Modify<ByTxHash>(it_prev, [](Announcement& ann){ ann.SetState(State::CANDIDATE_BEST); }); + } + } + Modify<ByTxHash>(it, [new_state](Announcement& ann){ ann.SetState(new_state); }); + } + + //! Check if 'it' is the only announcement for a given txhash that isn't COMPLETED. + bool IsOnlyNonCompleted(Iter<ByTxHash> it) + { + assert(it != m_index.get<ByTxHash>().end()); + assert(it->GetState() != State::COMPLETED); // Not allowed to call this on COMPLETED announcements. + + // This announcement has a predecessor that belongs to the same txhash. Due to ordering, and the + // fact that 'it' is not COMPLETED, its predecessor cannot be COMPLETED here. + if (it != m_index.get<ByTxHash>().begin() && std::prev(it)->m_txhash == it->m_txhash) return false; + + // This announcement has a successor that belongs to the same txhash, and is not COMPLETED. + if (std::next(it) != m_index.get<ByTxHash>().end() && std::next(it)->m_txhash == it->m_txhash && + std::next(it)->GetState() != State::COMPLETED) return false; + + return true; + } + + /** Convert any announcement to a COMPLETED one. If there are no non-COMPLETED announcements left for this + * txhash, they are deleted. If this was a REQUESTED announcement, and there are other CANDIDATEs left, the + * best one is made CANDIDATE_BEST. Returns whether the announcement still exists. */ + bool MakeCompleted(Iter<ByTxHash> it) + { + assert(it != m_index.get<ByTxHash>().end()); + + // Nothing to be done if it's already COMPLETED. + if (it->GetState() == State::COMPLETED) return true; + + if (IsOnlyNonCompleted(it)) { + // This is the last non-COMPLETED announcement for this txhash. Delete all. + uint256 txhash = it->m_txhash; + do { + it = Erase<ByTxHash>(it); + } while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash); + return false; + } + + // Mark the announcement COMPLETED, and select the next best announcement (the first CANDIDATE_READY) if + // needed. + ChangeAndReselect(it, State::COMPLETED); + + return true; + } + + //! Make the data structure consistent with a given point in time: + //! - REQUESTED annoucements with expiry <= now are turned into COMPLETED. + //! - CANDIDATE_DELAYED announcements with reqtime <= now are turned into CANDIDATE_{READY,BEST}. + //! - CANDIDATE_{READY,BEST} announcements with reqtime > now are turned into CANDIDATE_DELAYED. + void SetTimePoint(std::chrono::microseconds now, std::vector<std::pair<NodeId, GenTxid>>* expired) + { + if (expired) expired->clear(); + + // Iterate over all CANDIDATE_DELAYED and REQUESTED from old to new, as long as they're in the past, + // and convert them to CANDIDATE_READY and COMPLETED respectively. + while (!m_index.empty()) { + auto it = m_index.get<ByTime>().begin(); + if (it->GetState() == State::CANDIDATE_DELAYED && it->m_time <= now) { + PromoteCandidateReady(m_index.project<ByTxHash>(it)); + } else if (it->GetState() == State::REQUESTED && it->m_time <= now) { + if (expired) expired->emplace_back(it->m_peer, ToGenTxid(*it)); + MakeCompleted(m_index.project<ByTxHash>(it)); + } else { + break; + } + } + + while (!m_index.empty()) { + // If time went backwards, we may need to demote CANDIDATE_BEST and CANDIDATE_READY announcements back + // to CANDIDATE_DELAYED. This is an unusual edge case, and unlikely to matter in production. However, + // it makes it much easier to specify and test TxRequestTracker::Impl's behaviour. + auto it = std::prev(m_index.get<ByTime>().end()); + if (it->IsSelectable() && it->m_time > now) { + ChangeAndReselect(m_index.project<ByTxHash>(it), State::CANDIDATE_DELAYED); + } else { + break; + } + } + } + +public: + explicit Impl(bool deterministic) : + m_computer(deterministic), + // Explicitly initialize m_index as we need to pass a reference to m_computer to ByTxHashViewExtractor. + m_index(boost::make_tuple( + boost::make_tuple(ByPeerViewExtractor(), std::less<ByPeerView>()), + boost::make_tuple(ByTxHashViewExtractor(m_computer), std::less<ByTxHashView>()), + boost::make_tuple(ByTimeViewExtractor(), std::less<ByTimeView>()) + )) {} + + // Disable copying and assigning (a default copy won't work due the stateful ByTxHashViewExtractor). + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + + void DisconnectedPeer(NodeId peer) + { + auto& index = m_index.get<ByPeer>(); + auto it = index.lower_bound(ByPeerView{peer, false, uint256::ZERO}); + while (it != index.end() && it->m_peer == peer) { + // Check what to continue with after this iteration. 'it' will be deleted in what follows, so we need to + // decide what to continue with afterwards. There are a number of cases to consider: + // - std::next(it) is end() or belongs to a different peer. In that case, this is the last iteration + // of the loop (denote this by setting it_next to end()). + // - 'it' is not the only non-COMPLETED announcement for its txhash. This means it will be deleted, but + // no other Announcement objects will be modified. Continue with std::next(it) if it belongs to the + // same peer, but decide this ahead of time (as 'it' may change position in what follows). + // - 'it' is the only non-COMPLETED announcement for its txhash. This means it will be deleted along + // with all other announcements for the same txhash - which may include std::next(it). However, other + // than 'it', no announcements for the same peer can be affected (due to (peer, txhash) uniqueness). + // In other words, the situation where std::next(it) is deleted can only occur if std::next(it) + // belongs to a different peer but the same txhash as 'it'. This is covered by the first bulletpoint + // already, and we'll have set it_next to end(). + auto it_next = (std::next(it) == index.end() || std::next(it)->m_peer != peer) ? index.end() : + std::next(it); + // If the announcement isn't already COMPLETED, first make it COMPLETED (which will mark other + // CANDIDATEs as CANDIDATE_BEST, or delete all of a txhash's announcements if no non-COMPLETED ones are + // left). + if (MakeCompleted(m_index.project<ByTxHash>(it))) { + // Then actually delete the announcement (unless it was already deleted by MakeCompleted). + Erase<ByPeer>(it); + } + it = it_next; + } + } + + void ForgetTxHash(const uint256& txhash) + { + auto it = m_index.get<ByTxHash>().lower_bound(ByTxHashView{txhash, State::CANDIDATE_DELAYED, 0}); + while (it != m_index.get<ByTxHash>().end() && it->m_txhash == txhash) { + it = Erase<ByTxHash>(it); + } + } + + void ReceivedInv(NodeId peer, const GenTxid& gtxid, bool preferred, + std::chrono::microseconds reqtime) + { + // Bail out if we already have a CANDIDATE_BEST announcement for this (txhash, peer) combination. The case + // where there is a non-CANDIDATE_BEST announcement already will be caught by the uniqueness property of the + // ByPeer index when we try to emplace the new object below. + if (m_index.get<ByPeer>().count(ByPeerView{peer, true, gtxid.GetHash()})) return; + + // Try creating the announcement with CANDIDATE_DELAYED state (which will fail due to the uniqueness + // of the ByPeer index if a non-CANDIDATE_BEST announcement already exists with the same txhash and peer). + // Bail out in that case. + auto ret = m_index.get<ByPeer>().emplace(gtxid, peer, preferred, reqtime, m_current_sequence); + if (!ret.second) return; + + // Update accounting metadata. + ++m_peerinfo[peer].m_total; + ++m_current_sequence; + } + + //! Find the GenTxids to request now from peer. + std::vector<GenTxid> GetRequestable(NodeId peer, std::chrono::microseconds now, + std::vector<std::pair<NodeId, GenTxid>>* expired) + { + // Move time. + SetTimePoint(now, expired); + + // Find all CANDIDATE_BEST announcements for this peer. + std::vector<const Announcement*> selected; + auto it_peer = m_index.get<ByPeer>().lower_bound(ByPeerView{peer, true, uint256::ZERO}); + while (it_peer != m_index.get<ByPeer>().end() && it_peer->m_peer == peer && + it_peer->GetState() == State::CANDIDATE_BEST) { + selected.emplace_back(&*it_peer); + ++it_peer; + } + + // Sort by sequence number. + std::sort(selected.begin(), selected.end(), [](const Announcement* a, const Announcement* b) { + return a->m_sequence < b->m_sequence; + }); + + // Convert to GenTxid and return. + std::vector<GenTxid> ret; + ret.reserve(selected.size()); + std::transform(selected.begin(), selected.end(), std::back_inserter(ret), [](const Announcement* ann) { + return ToGenTxid(*ann); + }); + return ret; + } + + void RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds expiry) + { + auto it = m_index.get<ByPeer>().find(ByPeerView{peer, true, txhash}); + if (it == m_index.get<ByPeer>().end()) { + // There is no CANDIDATE_BEST announcement, look for a _READY or _DELAYED instead. If the caller only + // ever invokes RequestedTx with the values returned by GetRequestable, and no other non-const functions + // other than ForgetTxHash and GetRequestable in between, this branch will never execute (as txhashes + // returned by GetRequestable always correspond to CANDIDATE_BEST announcements). + + it = m_index.get<ByPeer>().find(ByPeerView{peer, false, txhash}); + if (it == m_index.get<ByPeer>().end() || (it->GetState() != State::CANDIDATE_DELAYED && + it->GetState() != State::CANDIDATE_READY)) { + // There is no CANDIDATE announcement tracked for this peer, so we have nothing to do. Either this + // txhash wasn't tracked at all (and the caller should have called ReceivedInv), or it was already + // requested and/or completed for other reasons and this is just a superfluous RequestedTx call. + return; + } + + // Look for an existing CANDIDATE_BEST or REQUESTED with the same txhash. We only need to do this if the + // found announcement had a different state than CANDIDATE_BEST. If it did, invariants guarantee that no + // other CANDIDATE_BEST or REQUESTED can exist. + auto it_old = m_index.get<ByTxHash>().lower_bound(ByTxHashView{txhash, State::CANDIDATE_BEST, 0}); + if (it_old != m_index.get<ByTxHash>().end() && it_old->m_txhash == txhash) { + if (it_old->GetState() == State::CANDIDATE_BEST) { + // The data structure's invariants require that there can be at most one CANDIDATE_BEST or one + // REQUESTED announcement per txhash (but not both simultaneously), so we have to convert any + // existing CANDIDATE_BEST to another CANDIDATE_* when constructing another REQUESTED. + // It doesn't matter whether we pick CANDIDATE_READY or _DELAYED here, as SetTimePoint() + // will correct it at GetRequestable() time. If time only goes forward, it will always be + // _READY, so pick that to avoid extra work in SetTimePoint(). + Modify<ByTxHash>(it_old, [](Announcement& ann) { ann.SetState(State::CANDIDATE_READY); }); + } else if (it_old->GetState() == State::REQUESTED) { + // As we're no longer waiting for a response to the previous REQUESTED announcement, convert it + // to COMPLETED. This also helps guaranteeing progress. + Modify<ByTxHash>(it_old, [](Announcement& ann) { ann.SetState(State::COMPLETED); }); + } + } + } + + Modify<ByPeer>(it, [expiry](Announcement& ann) { + ann.SetState(State::REQUESTED); + ann.m_time = expiry; + }); + } + + void ReceivedResponse(NodeId peer, const uint256& txhash) + { + // We need to search the ByPeer index for both (peer, false, txhash) and (peer, true, txhash). + auto it = m_index.get<ByPeer>().find(ByPeerView{peer, false, txhash}); + if (it == m_index.get<ByPeer>().end()) { + it = m_index.get<ByPeer>().find(ByPeerView{peer, true, txhash}); + } + if (it != m_index.get<ByPeer>().end()) MakeCompleted(m_index.project<ByTxHash>(it)); + } + + size_t CountInFlight(NodeId peer) const + { + auto it = m_peerinfo.find(peer); + if (it != m_peerinfo.end()) return it->second.m_requested; + return 0; + } + + size_t CountCandidates(NodeId peer) const + { + auto it = m_peerinfo.find(peer); + if (it != m_peerinfo.end()) return it->second.m_total - it->second.m_requested - it->second.m_completed; + return 0; + } + + size_t Count(NodeId peer) const + { + auto it = m_peerinfo.find(peer); + if (it != m_peerinfo.end()) return it->second.m_total; + return 0; + } + + //! Count how many announcements are being tracked in total across all peers and transactions. + size_t Size() const { return m_index.size(); } + + uint64_t ComputePriority(const uint256& txhash, NodeId peer, bool preferred) const + { + // Return Priority as a uint64_t as Priority is internal. + return uint64_t{m_computer(txhash, peer, preferred)}; + } + +}; + +TxRequestTracker::TxRequestTracker(bool deterministic) : + m_impl{MakeUnique<TxRequestTracker::Impl>(deterministic)} {} + +TxRequestTracker::~TxRequestTracker() = default; + +void TxRequestTracker::ForgetTxHash(const uint256& txhash) { m_impl->ForgetTxHash(txhash); } +void TxRequestTracker::DisconnectedPeer(NodeId peer) { m_impl->DisconnectedPeer(peer); } +size_t TxRequestTracker::CountInFlight(NodeId peer) const { return m_impl->CountInFlight(peer); } +size_t TxRequestTracker::CountCandidates(NodeId peer) const { return m_impl->CountCandidates(peer); } +size_t TxRequestTracker::Count(NodeId peer) const { return m_impl->Count(peer); } +size_t TxRequestTracker::Size() const { return m_impl->Size(); } +void TxRequestTracker::SanityCheck() const { m_impl->SanityCheck(); } + +void TxRequestTracker::PostGetRequestableSanityCheck(std::chrono::microseconds now) const +{ + m_impl->PostGetRequestableSanityCheck(now); +} + +void TxRequestTracker::ReceivedInv(NodeId peer, const GenTxid& gtxid, bool preferred, + std::chrono::microseconds reqtime) +{ + m_impl->ReceivedInv(peer, gtxid, preferred, reqtime); +} + +void TxRequestTracker::RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds expiry) +{ + m_impl->RequestedTx(peer, txhash, expiry); +} + +void TxRequestTracker::ReceivedResponse(NodeId peer, const uint256& txhash) +{ + m_impl->ReceivedResponse(peer, txhash); +} + +std::vector<GenTxid> TxRequestTracker::GetRequestable(NodeId peer, std::chrono::microseconds now, + std::vector<std::pair<NodeId, GenTxid>>* expired) +{ + return m_impl->GetRequestable(peer, now, expired); +} + +uint64_t TxRequestTracker::ComputePriority(const uint256& txhash, NodeId peer, bool preferred) const +{ + return m_impl->ComputePriority(txhash, peer, preferred); +} diff --git a/src/txrequest.h b/src/txrequest.h new file mode 100644 index 0000000000..cd3042c87e --- /dev/null +++ b/src/txrequest.h @@ -0,0 +1,211 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_TXREQUEST_H +#define BITCOIN_TXREQUEST_H + +#include <primitives/transaction.h> +#include <net.h> // For NodeId +#include <uint256.h> + +#include <chrono> +#include <vector> + +#include <stdint.h> + +/** Data structure to keep track of, and schedule, transaction downloads from peers. + * + * === Specification === + * + * We keep track of which peers have announced which transactions, and use that to determine which requests + * should go to which peer, when, and in what order. + * + * The following information is tracked per peer/tx combination ("announcement"): + * - Which peer announced it (through their NodeId) + * - The txid or wtxid of the transaction (collectively called "txhash" in what follows) + * - Whether it was a tx or wtx announcement (see BIP339). + * - What the earliest permitted time is that that transaction can be requested from that peer (called "reqtime"). + * - Whether it's from a "preferred" peer or not. Which announcements get this flag is determined by the caller, but + * this is designed for outbound peers, or other peers that we have a higher level of trust in. Even when the + * peers' preferredness changes, the preferred flag of existing announcements from that peer won't change. + * - Whether or not the transaction was requested already, and if so, when it times out (called "expiry"). + * - Whether or not the transaction request failed already (timed out, or invalid transaction or NOTFOUND was + * received). + * + * Transaction requests are then assigned to peers, following these rules: + * + * - No transaction is requested as long as another request for the same txhash is outstanding (it needs to fail + * first by passing expiry, or a NOTFOUND or invalid transaction has to be received for it). + * + * Rationale: to avoid wasting bandwidth on multiple copies of the same transaction. Note that this only works + * per txhash, so if the same transaction is announced both through txid and wtxid, we have no means + * to prevent fetching both (the caller can however mitigate this by delaying one, see further). + * + * - The same transaction is never requested twice from the same peer, unless the announcement was forgotten in + * between, and re-announced. Announcements are forgotten only: + * - If a peer goes offline, all its announcements are forgotten. + * - If a transaction has been successfully received, or is otherwise no longer needed, the caller can call + * ForgetTxHash, which removes all announcements across all peers with the specified txhash. + * - If for a given txhash only already-failed announcements remain, they are all forgotten. + * + * Rationale: giving a peer multiple chances to announce a transaction would allow them to bias requests in their + * favor, worsening transaction censoring attacks. The flip side is that as long as an attacker manages + * to prevent us from receiving a transaction, failed announcements (including those from honest peers) + * will linger longer, increasing memory usage somewhat. The impact of this is limited by imposing a + * cap on the number of tracked announcements per peer. As failed requests in response to announcements + * from honest peers should be rare, this almost solely hinders attackers. + * Transaction censoring attacks can be done by announcing transactions quickly while not answering + * requests for them. See https://allquantor.at/blockchainbib/pdf/miller2015topology.pdf for more + * information. + * + * - Transactions are not requested from a peer until its reqtime has passed. + * + * Rationale: enable the calling code to define a delay for less-than-ideal peers, so that (presumed) better + * peers have a chance to give their announcement first. + * + * - If multiple viable candidate peers exist according to the above rules, pick a peer as follows: + * + * - If any preferred peers are available, non-preferred peers are not considered for what follows. + * + * Rationale: preferred peers are more trusted by us, so are less likely to be under attacker control. + * + * - Pick a uniformly random peer among the candidates. + * + * Rationale: random assignments are hard to influence for attackers. + * + * Together these rules strike a balance between being fast in non-adverserial conditions and minimizing + * susceptibility to censorship attacks. An attacker that races the network: + * - Will be unsuccessful if all preferred connections are honest (and there is at least one preferred connection). + * - If there are P preferred connections of which Ph>=1 are honest, the attacker can delay us from learning + * about a transaction by k expiration periods, where k ~ 1 + NHG(N=P-1,K=P-Ph-1,r=1), which has mean + * P/(Ph+1) (where NHG stands for Negative Hypergeometric distribution). The "1 +" is due to the fact that the + * attacker can be the first to announce through a preferred connection in this scenario, which very likely means + * they get the first request. + * - If all P preferred connections are to the attacker, and there are NP non-preferred connections of which NPh>=1 + * are honest, where we assume that the attacker can disconnect and reconnect those connections, the distribution + * becomes k ~ P + NB(p=1-NPh/NP,r=1) (where NB stands for Negative Binomial distribution), which has mean + * P-1+NP/NPh. + * + * Complexity: + * - Memory usage is proportional to the total number of tracked announcements (Size()) plus the number of + * peers with a nonzero number of tracked announcements. + * - CPU usage is generally logarithmic in the total number of tracked announcements, plus the number of + * announcements affected by an operation (amortized O(1) per announcement). + */ +class TxRequestTracker { + // Avoid littering this header file with implementation details. + class Impl; + const std::unique_ptr<Impl> m_impl; + +public: + //! Construct a TxRequestTracker. + explicit TxRequestTracker(bool deterministic = false); + ~TxRequestTracker(); + + // Conceptually, the data structure consists of a collection of "announcements", one for each peer/txhash + // combination: + // + // - CANDIDATE announcements represent transactions that were announced by a peer, and that become available for + // download after their reqtime has passed. + // + // - REQUESTED announcements represent transactions that have been requested, and which we're awaiting a + // response for from that peer. Their expiry value determines when the request times out. + // + // - COMPLETED announcements represent transactions that have been requested from a peer, and a NOTFOUND or a + // transaction was received in response (valid or not), or they timed out. They're only kept around to + // prevent requesting them again. If only COMPLETED announcements for a given txhash remain (so no CANDIDATE + // or REQUESTED ones), all of them are deleted (this is an invariant, and maintained by all operations below). + // + // The operations below manipulate the data structure. + + /** Adds a new CANDIDATE announcement. + * + * Does nothing if one already exists for that (txhash, peer) combination (whether it's CANDIDATE, REQUESTED, or + * COMPLETED). Note that the txid/wtxid property is ignored for determining uniqueness, so if an announcement + * is added for a wtxid H, while one for txid H from the same peer already exists, it will be ignored. This is + * harmless as the txhashes being equal implies it is a non-segwit transaction, so it doesn't matter how it is + * fetched. The new announcement is given the specified preferred and reqtime values, and takes its is_wtxid + * from the specified gtxid. + */ + void ReceivedInv(NodeId peer, const GenTxid& gtxid, bool preferred, + std::chrono::microseconds reqtime); + + /** Deletes all announcements for a given peer. + * + * It should be called when a peer goes offline. + */ + void DisconnectedPeer(NodeId peer); + + /** Deletes all announcements for a given txhash (both txid and wtxid ones). + * + * This should be called when a transaction is no longer needed. The caller should ensure that new announcements + * for the same txhash will not trigger new ReceivedInv calls, at least in the short term after this call. + */ + void ForgetTxHash(const uint256& txhash); + + /** Find the txids to request now from peer. + * + * It does the following: + * - Convert all REQUESTED announcements (for all txhashes/peers) with (expiry <= now) to COMPLETED ones. + * These are returned in expired, if non-nullptr. + * - Requestable announcements are selected: CANDIDATE announcements from the specified peer with + * (reqtime <= now) for which no existing REQUESTED announcement with the same txhash from a different peer + * exists, and for which the specified peer is the best choice among all (reqtime <= now) CANDIDATE + * announcements with the same txhash (subject to preferredness rules, and tiebreaking using a deterministic + * salted hash of peer and txhash). + * - The selected announcements are converted to GenTxids using their is_wtxid flag, and returned in + * announcement order (even if multiple were added at the same time, or when the clock went backwards while + * they were being added). This is done to minimize disruption from dependent transactions being requested + * out of order: if multiple dependent transactions are announced simultaneously by one peer, and end up + * being requested from them, the requests will happen in announcement order. + */ + std::vector<GenTxid> GetRequestable(NodeId peer, std::chrono::microseconds now, + std::vector<std::pair<NodeId, GenTxid>>* expired = nullptr); + + /** Marks a transaction as requested, with a specified expiry. + * + * If no CANDIDATE announcement for the provided peer and txhash exists, this call has no effect. Otherwise: + * - That announcement is converted to REQUESTED. + * - If any other REQUESTED announcement for the same txhash already existed, it means an unexpected request + * was made (GetRequestable will never advise doing so). In this case it is converted to COMPLETED, as we're + * no longer waiting for a response to it. + */ + void RequestedTx(NodeId peer, const uint256& txhash, std::chrono::microseconds expiry); + + /** Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one. If no such announcement exists for the + * provided peer and txhash, nothing happens. + * + * It should be called whenever a transaction or NOTFOUND was received from a peer. When the transaction is + * not needed entirely anymore, ForgetTxhash should be called instead of, or in addition to, this call. + */ + void ReceivedResponse(NodeId peer, const uint256& txhash); + + // The operations below inspect the data structure. + + /** Count how many REQUESTED announcements a peer has. */ + size_t CountInFlight(NodeId peer) const; + + /** Count how many CANDIDATE announcements a peer has. */ + size_t CountCandidates(NodeId peer) const; + + /** Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined). */ + size_t Count(NodeId peer) const; + + /** Count how many announcements are being tracked in total across all peers and transaction hashes. */ + size_t Size() const; + + /** Access to the internal priority computation (testing only) */ + uint64_t ComputePriority(const uint256& txhash, NodeId peer, bool preferred) const; + + /** Run internal consistency check (testing only). */ + void SanityCheck() const; + + /** Run a time-dependent internal consistency check (testing only). + * + * This can only be called immediately after GetRequestable, with the same 'now' parameter. + */ + void PostGetRequestableSanityCheck(std::chrono::microseconds now) const; +}; + +#endif // BITCOIN_TXREQUEST_H diff --git a/src/uint256.cpp b/src/uint256.cpp index d074df2f20..cd9cbb566a 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -80,4 +80,5 @@ template std::string base_blob<256>::ToString() const; template void base_blob<256>::SetHex(const char*); template void base_blob<256>::SetHex(const std::string&); +const uint256 uint256::ZERO(0); const uint256 uint256::ONE(1); diff --git a/src/uint256.h b/src/uint256.h index c55cb31456..fadf2320af 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -126,6 +126,7 @@ public: constexpr uint256() {} constexpr explicit uint256(uint8_t v) : base_blob<256>(v) {} explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {} + static const uint256 ZERO; static const uint256 ONE; }; diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index 6080516353..048e162f7d 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -100,6 +100,10 @@ public: UniValue tmpVal(val_); return push_back(tmpVal); } + bool push_back(bool val_) { + UniValue tmpVal(val_); + return push_back(tmpVal); + } bool push_back(int val_) { UniValue tmpVal(val_); return push_back(tmpVal); @@ -129,7 +133,7 @@ public: return pushKV(key, tmpVal); } bool pushKV(const std::string& key, bool val_) { - UniValue tmpVal((bool)val_); + UniValue tmpVal(val_); return pushKV(key, tmpVal); } bool pushKV(const std::string& key, int val_) { diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp index 70ccc0d08a..ccc1344836 100644 --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -210,19 +210,31 @@ BOOST_AUTO_TEST_CASE(univalue_array) BOOST_CHECK(arr.push_back((int64_t) -400LL)); BOOST_CHECK(arr.push_back((int) -401)); BOOST_CHECK(arr.push_back(-40.1)); + BOOST_CHECK(arr.push_back(true)); BOOST_CHECK_EQUAL(arr.empty(), false); - BOOST_CHECK_EQUAL(arr.size(), 9); + BOOST_CHECK_EQUAL(arr.size(), 10); BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023"); + BOOST_CHECK_EQUAL(arr[0].getType(), UniValue::VNUM); BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[1].getType(), UniValue::VSTR); BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[2].getType(), UniValue::VSTR); BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[3].getType(), UniValue::VSTR); BOOST_CHECK_EQUAL(arr[4].getValStr(), "going"); + BOOST_CHECK_EQUAL(arr[4].getType(), UniValue::VSTR); BOOST_CHECK_EQUAL(arr[5].getValStr(), "400"); + BOOST_CHECK_EQUAL(arr[5].getType(), UniValue::VNUM); BOOST_CHECK_EQUAL(arr[6].getValStr(), "-400"); + BOOST_CHECK_EQUAL(arr[6].getType(), UniValue::VNUM); BOOST_CHECK_EQUAL(arr[7].getValStr(), "-401"); + BOOST_CHECK_EQUAL(arr[7].getType(), UniValue::VNUM); BOOST_CHECK_EQUAL(arr[8].getValStr(), "-40.1"); + BOOST_CHECK_EQUAL(arr[8].getType(), UniValue::VNUM); + BOOST_CHECK_EQUAL(arr[9].getValStr(), "1"); + BOOST_CHECK_EQUAL(arr[9].getType(), UniValue::VBOOL); BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); diff --git a/src/util/asmap.h b/src/util/asmap.h index b31e639bb5..d0588bc8c3 100644 --- a/src/util/asmap.h +++ b/src/util/asmap.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/bip32.h b/src/util/bip32.h index 347e83db9e..8f86f2aaa6 100644 --- a/src/util/bip32.h +++ b/src/util/bip32.h @@ -10,7 +10,7 @@ #include <vector> /** Parse an HD keypaths like "m/7/0'/2000". */ -NODISCARD bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); +[[nodiscard]] bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); /** Write HD keypaths as strings */ std::string WriteHDKeypath(const std::vector<uint32_t>& keypath); diff --git a/src/util/check.h b/src/util/check.h index 9edf394492..bc62da3440 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -46,7 +46,7 @@ class NonFatalCheckError : public std::runtime_error #error "Cannot compile without assertions!" #endif -/** Helper for Assert(). TODO remove in C++14 and replace `decltype(get_pure_r_value(val))` with `T` (templated lambda) */ +/** Helper for Assert() */ template <typename T> T get_pure_r_value(T&& val) { @@ -54,6 +54,22 @@ T get_pure_r_value(T&& val) } /** Identity function. Abort if the value compares equal to zero */ -#define Assert(val) [&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }() +#define Assert(val) ([&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }()) + +/** + * Assume is the identity function. + * + * - Should be used to run non-fatal checks. In debug builds it behaves like + * Assert()/assert() to notify developers and testers about non-fatal errors. + * In production it doesn't warn or log anything. + * - For fatal errors, use Assert(). + * - For non-fatal errors in interactive sessions (e.g. RPC or command line + * interfaces), CHECK_NONFATAL() might be more appropriate. + */ +#ifdef ABORT_ON_FAILED_ASSUME +#define Assume(val) Assert(val) +#else +#define Assume(val) ((void)(val)) +#endif #endif // BITCOIN_UTIL_CHECK_H diff --git a/src/util/error.cpp b/src/util/error.cpp index 3e29083712..76fac4d391 100644 --- a/src/util/error.cpp +++ b/src/util/error.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2019 The Bitcoin Core developers +// Copyright (c) 2010-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -30,7 +30,7 @@ bilingual_str TransactionErrorString(const TransactionError err) case TransactionError::SIGHASH_MISMATCH: return Untranslated("Specified sighash value does not match value stored in PSBT"); case TransactionError::MAX_FEE_EXCEEDED: - return Untranslated("Fee exceeds maximum configured by -maxtxfee"); + return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"); // no default case, so the compiler can warn about missing cases } assert(false); diff --git a/src/util/error.h b/src/util/error.h index b9830c9eea..6633498d2b 100644 --- a/src/util/error.h +++ b/src/util/error.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2019 The Bitcoin Core developers +// Copyright (c) 2010-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/fees.cpp b/src/util/fees.cpp index 6208a20a97..cbefe18dbb 100644 --- a/src/util/fees.cpp +++ b/src/util/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,8 +40,6 @@ const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap() {"unset", FeeEstimateMode::UNSET}, {"economical", FeeEstimateMode::ECONOMICAL}, {"conservative", FeeEstimateMode::CONSERVATIVE}, - {(CURRENCY_UNIT + "/kB"), FeeEstimateMode::BTC_KB}, - {(CURRENCY_ATOM + "/B"), FeeEstimateMode::SAT_B}, }; return FEE_MODES; } @@ -51,6 +49,11 @@ std::string FeeModes(const std::string& delimiter) return Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; }); } +const std::string InvalidEstimateModeErrorMessage() +{ + return "Invalid estimate_mode parameter, must be one of: \"" + FeeModes("\", \"") + "\""; +} + bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) { auto searchkey = ToUpper(mode_string); diff --git a/src/util/fees.h b/src/util/fees.h index d52046a44c..9ef2389d3e 100644 --- a/src/util/fees.h +++ b/src/util/fees.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UTIL_FEES_H @@ -13,5 +13,6 @@ enum class FeeReason; bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode); std::string StringForFeeReason(FeeReason reason); std::string FeeModes(const std::string& delimiter); +const std::string InvalidEstimateModeErrorMessage(); #endif // BITCOIN_UTIL_FEES_H diff --git a/src/util/golombrice.h b/src/util/golombrice.h index 425e7f6681..67d262406f 100644 --- a/src/util/golombrice.h +++ b/src/util/golombrice.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp new file mode 100644 index 0000000000..5900daf050 --- /dev/null +++ b/src/util/hasher.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <random.h> +#include <util/hasher.h> + +#include <limits> + +SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {} + +SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {} + +SaltedSipHasher::SaltedSipHasher() : m_k0(GetRand(std::numeric_limits<uint64_t>::max())), m_k1(GetRand(std::numeric_limits<uint64_t>::max())) {} + +size_t SaltedSipHasher::operator()(const Span<const unsigned char>& script) const +{ + return CSipHasher(m_k0, m_k1).Write(script.data(), script.size()).Finalize(); +} diff --git a/src/util/hasher.h b/src/util/hasher.h new file mode 100644 index 0000000000..fa2fea30d8 --- /dev/null +++ b/src/util/hasher.h @@ -0,0 +1,99 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_HASHER_H +#define BITCOIN_UTIL_HASHER_H + +#include <crypto/siphash.h> +#include <primitives/transaction.h> +#include <uint256.h> + +class SaltedTxidHasher +{ +private: + /** Salt */ + const uint64_t k0, k1; + +public: + SaltedTxidHasher(); + + size_t operator()(const uint256& txid) const { + return SipHashUint256(k0, k1, txid); + } +}; + +class SaltedOutpointHasher +{ +private: + /** Salt */ + const uint64_t k0, k1; + +public: + SaltedOutpointHasher(); + + /** + * This *must* return size_t. With Boost 1.46 on 32-bit systems the + * unordered_map will behave unpredictably if the custom hasher returns a + * uint64_t, resulting in failures when syncing the chain (#4634). + * + * Having the hash noexcept allows libstdc++'s unordered_map to recalculate + * the hash during rehash, so it does not have to cache the value. This + * reduces node's memory by sizeof(size_t). The required recalculation has + * a slight performance penalty (around 1.6%), but this is compensated by + * memory savings of about 9% which allow for a larger dbcache setting. + * + * @see https://gcc.gnu.org/onlinedocs/gcc-9.2.0/libstdc++/manual/manual/unordered_associative.html + */ + size_t operator()(const COutPoint& id) const noexcept { + return SipHashUint256Extra(k0, k1, id.hash, id.n); + } +}; + +struct FilterHeaderHasher +{ + size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } +}; + +/** + * We're hashing a nonce into the entries themselves, so we don't need extra + * blinding in the set hash computation. + * + * This may exhibit platform endian dependent behavior but because these are + * nonced hashes (random) and this state is only ever used locally it is safe. + * All that matters is local consistency. + */ +class SignatureCacheHasher +{ +public: + template <uint8_t hash_select> + uint32_t operator()(const uint256& key) const + { + static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available."); + uint32_t u; + std::memcpy(&u, key.begin()+4*hash_select, 4); + return u; + } +}; + +struct BlockHasher +{ + // this used to call `GetCheapHash()` in uint256, which was later moved; the + // cheap hash function simply calls ReadLE64() however, so the end result is + // identical + size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } +}; + +class SaltedSipHasher +{ +private: + /** Salt */ + const uint64_t m_k0, m_k1; + +public: + SaltedSipHasher(); + + size_t operator()(const Span<const unsigned char>& script) const; +}; + +#endif // BITCOIN_UTIL_HASHER_H diff --git a/src/util/memory.h b/src/util/memory.h index 15ecf8f80d..f21b81bade 100644 --- a/src/util/memory.h +++ b/src/util/memory.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,10 +10,11 @@ #include <utility> //! Substitute for C++14 std::make_unique. +//! DEPRECATED use std::make_unique in new code. template <typename T, typename... Args> std::unique_ptr<T> MakeUnique(Args&&... args) { - return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + return std::make_unique<T>(std::forward<Args>(args)...); } #endif diff --git a/src/util/message.cpp b/src/util/message.cpp index e1d5cff48c..73948e4ff1 100644 --- a/src/util/message.cpp +++ b/src/util/message.cpp @@ -31,7 +31,7 @@ MessageVerificationResult MessageVerify( return MessageVerificationResult::ERR_INVALID_ADDRESS; } - if (boost::get<PKHash>(&destination) == nullptr) { + if (std::get_if<PKHash>(&destination) == nullptr) { return MessageVerificationResult::ERR_ADDRESS_NO_KEY; } diff --git a/src/util/moneystr.h b/src/util/moneystr.h index 9d2b6da0fc..da7f673cda 100644 --- a/src/util/moneystr.h +++ b/src/util/moneystr.h @@ -19,6 +19,6 @@ */ std::string FormatMoney(const CAmount& n); /** Parse an amount denoted in full coins. E.g. "0.0034" supplied on the command line. **/ -NODISCARD bool ParseMoney(const std::string& str, CAmount& nRet); +[[nodiscard]] bool ParseMoney(const std::string& str, CAmount& nRet); #endif // BITCOIN_UTIL_MONEYSTR_H diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 3236184b0b..f3d54a2ac9 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -280,7 +280,7 @@ std::string DecodeBase32(const std::string& str, bool* pf_invalid) return std::string((const char*)vchRet.data(), vchRet.size()); } -NODISCARD static bool ParsePrechecks(const std::string& str) +[[nodiscard]] static bool ParsePrechecks(const std::string& str) { if (str.empty()) // No empty string allowed return false; diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 1a217dd12d..b4a61202ef 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -101,42 +101,42 @@ constexpr inline bool IsSpace(char c) noexcept { * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -NODISCARD bool ParseInt32(const std::string& str, int32_t *out); +[[nodiscard]] bool ParseInt32(const std::string& str, int32_t *out); /** * Convert string to signed 64-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -NODISCARD bool ParseInt64(const std::string& str, int64_t *out); +[[nodiscard]] bool ParseInt64(const std::string& str, int64_t *out); /** * Convert decimal string to unsigned 8-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -NODISCARD bool ParseUInt8(const std::string& str, uint8_t *out); +[[nodiscard]] bool ParseUInt8(const std::string& str, uint8_t *out); /** * Convert decimal string to unsigned 32-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -NODISCARD bool ParseUInt32(const std::string& str, uint32_t *out); +[[nodiscard]] bool ParseUInt32(const std::string& str, uint32_t *out); /** * Convert decimal string to unsigned 64-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -NODISCARD bool ParseUInt64(const std::string& str, uint64_t *out); +[[nodiscard]] bool ParseUInt64(const std::string& str, uint64_t *out); /** * Convert string to double with strict parse error feedback. * @returns true if the entire string could be parsed as valid double, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -NODISCARD bool ParseDouble(const std::string& str, double *out); +[[nodiscard]] bool ParseDouble(const std::string& str, double *out); /** * Convert a span of bytes to a lower-case hexadecimal string. @@ -166,11 +166,11 @@ bool TimingResistantEqual(const T& a, const T& b) } /** Parse number as fixed point according to JSON number syntax. - * See http://json.org/number.gif + * See https://json.org/number.gif * @returns true on success, false on error. * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger. */ -NODISCARD bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); +[[nodiscard]] bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); /** Convert from one power-of-2 number base to another. */ template<int frombits, int tobits, bool pad, typename O, typename I> diff --git a/src/util/string.h b/src/util/string.h index a0c87bd00c..5ffdc80d88 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -15,7 +15,7 @@ #include <string> #include <vector> -NODISCARD inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v") +[[nodiscard]] inline std::string TrimString(const std::string& str, const std::string& pattern = " \f\n\r\t\v") { std::string::size_type front = str.find_first_not_of(pattern); if (front == std::string::npos) { @@ -59,7 +59,7 @@ inline std::string Join(const std::vector<std::string>& list, const std::string& /** * Check if a string does not contain any embedded NUL (\0) characters */ -NODISCARD inline bool ValidAsCString(const std::string& str) noexcept +[[nodiscard]] inline bool ValidAsCString(const std::string& str) noexcept { return str.size() == strlen(str.c_str()); } @@ -80,7 +80,7 @@ std::string ToString(const T& t) * Check whether a container begins with the given prefix. */ template <typename T1, size_t PREFIX_LEN> -NODISCARD inline bool HasPrefix(const T1& obj, +[[nodiscard]] inline bool HasPrefix(const T1& obj, const std::array<uint8_t, PREFIX_LEN>& prefix) { return obj.size() >= PREFIX_LEN && diff --git a/src/util/system.cpp b/src/util/system.cpp index 41715aac1a..d1fb921642 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -34,6 +34,7 @@ #endif // __linux__ #include <algorithm> +#include <cassert> #include <fcntl.h> #include <sched.h> #include <sys/resource.h> @@ -397,7 +398,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const } if (filepath) { std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME); - *filepath = fs::absolute(temp ? settings + ".tmp" : settings, GetDataDir(/* net_specific= */ true)); + *filepath = fsbridge::AbsPathJoin(GetDataDir(/* net_specific= */ true), temp ? settings + ".tmp" : settings); } return true; } @@ -427,6 +428,14 @@ bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors) SaveErrors(read_errors, errors); return false; } + for (const auto& setting : m_settings.rw_settings) { + std::string section; + std::string key = setting.first; + (void)InterpretOption(section, key, /* value */ {}); // Split setting key into section and argname + if (!GetArgFlags('-' + key)) { + LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first); + } + } return true; } @@ -523,7 +532,7 @@ void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names) std::string ArgsManager::GetHelpMessage() const { - const bool show_debug = gArgs.GetBoolArg("-help-debug", false); + const bool show_debug = GetBoolArg("-help-debug", false); std::string usage = ""; LOCK(cs_args); @@ -641,10 +650,9 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread) fs::path GetDefaultDataDir() { - // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin - // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin - // Mac: ~/Library/Application Support/Bitcoin - // Unix: ~/.bitcoin + // Windows: C:\Users\Username\AppData\Roaming\Bitcoin + // macOS: ~/Library/Application Support/Bitcoin + // Unix-like: ~/.bitcoin #ifdef WIN32 // Windows return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; @@ -656,15 +664,28 @@ fs::path GetDefaultDataDir() else pathRet = fs::path(pszHome); #ifdef MAC_OSX - // Mac + // macOS return pathRet / "Library/Application Support/Bitcoin"; #else - // Unix + // Unix-like return pathRet / ".bitcoin"; #endif #endif } +namespace { +fs::path StripRedundantLastElementsOfPath(const fs::path& path) +{ + auto result = path; + while (result.filename().string() == ".") { + result = result.parent_path(); + } + + assert(fs::equivalent(result, path)); + return result; +} +} // namespace + static fs::path g_blocks_path_cache_net_specific; static fs::path pathCached; static fs::path pathCachedNetSpecific; @@ -692,6 +713,7 @@ const fs::path &GetBlocksDir() path /= BaseParams().DataDir(); path /= "blocks"; fs::create_directories(path); + path = StripRedundantLastElementsOfPath(path); return path; } @@ -722,6 +744,7 @@ const fs::path &GetDataDir(bool fNetSpecific) fs::create_directories(path / "wallets"); } + path = StripRedundantLastElementsOfPath(path); return path; } @@ -900,7 +923,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) // If datadir is changed in .conf file: ClearDatadirCache(); if (!CheckDataDirOption()) { - error = strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "")); + error = strprintf("specified data directory \"%s\" does not exist.", GetArg("-datadir", "")); return false; } return true; @@ -1024,27 +1047,36 @@ bool FileCommit(FILE *file) LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError()); return false; } -#else - #if HAVE_FDATASYNC - if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync - LogPrintf("%s: fdatasync failed: %d\n", __func__, errno); - return false; - } - #elif defined(MAC_OSX) && defined(F_FULLFSYNC) +#elif defined(MAC_OSX) && defined(F_FULLFSYNC) if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno); return false; } - #else +#elif HAVE_FDATASYNC + if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync + LogPrintf("%s: fdatasync failed: %d\n", __func__, errno); + return false; + } +#else if (fsync(fileno(file)) != 0 && errno != EINVAL) { LogPrintf("%s: fsync failed: %d\n", __func__, errno); return false; } - #endif #endif return true; } +void DirectoryCommit(const fs::path &dirname) +{ +#ifndef WIN32 + FILE* file = fsbridge::fopen(dirname, "r"); + if (file) { + fsync(fileno(file)); + fclose(file); + } +#endif +} + bool TruncateFile(FILE *file, unsigned int length) { #if defined(WIN32) return _chsize(_fileno(file), length) == 0; @@ -1279,7 +1311,7 @@ fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific) if (path.is_absolute()) { return path; } - return fs::absolute(path, GetDataDir(net_specific)); + return fsbridge::AbsPathJoin(GetDataDir(net_specific), path); } void ScheduleBatchPriority() diff --git a/src/util/system.h b/src/util/system.h index 1df194ca84..010fc5b49f 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -56,11 +56,23 @@ bool error(const char* fmt, const Args&... args) } void PrintExceptionContinue(const std::exception *pex, const char* pszThread); + +/** + * Ensure file contents are fully committed to disk, using a platform-specific + * feature analogous to fsync(). + */ bool FileCommit(FILE *file); + +/** + * Sync directory contents. This is required on some environments to ensure that + * newly created files are committed to disk. + */ +void DirectoryCommit(const fs::path &dirname); + bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); -bool RenameOver(fs::path src, fs::path dest); +[[nodiscard]] 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); @@ -188,7 +200,7 @@ protected: std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args); std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args); - NODISCARD bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false); + [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false); /** * Returns true if settings values from the default section should be used, @@ -220,8 +232,8 @@ public: */ void SelectConfigNetwork(const std::string& network); - NODISCARD bool ParseParameters(int argc, const char* const argv[], std::string& error); - NODISCARD bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false); + [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error); + [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false); /** * Log warnings for options in m_section_only_args when diff --git a/src/util/time.h b/src/util/time.h index af934e423b..c69f604dc6 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -6,9 +6,11 @@ #ifndef BITCOIN_UTIL_TIME_H #define BITCOIN_UTIL_TIME_H +#include <chrono> #include <stdint.h> #include <string> -#include <chrono> + +using namespace std::chrono_literals; void UninterruptibleSleep(const std::chrono::microseconds& n); diff --git a/src/util/trace.h b/src/util/trace.h new file mode 100644 index 0000000000..9c92cb10e7 --- /dev/null +++ b/src/util/trace.h @@ -0,0 +1,45 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_TRACE_H +#define BITCOIN_UTIL_TRACE_H + +#ifdef ENABLE_TRACING + +#include <sys/sdt.h> + +#define TRACE(context, event) DTRACE_PROBE(context, event) +#define TRACE1(context, event, a) DTRACE_PROBE1(context, event, a) +#define TRACE2(context, event, a, b) DTRACE_PROBE2(context, event, a, b) +#define TRACE3(context, event, a, b, c) DTRACE_PROBE3(context, event, a, b, c) +#define TRACE4(context, event, a, b, c, d) DTRACE_PROBE4(context, event, a, b, c, d) +#define TRACE5(context, event, a, b, c, d, e) DTRACE_PROBE5(context, event, a, b, c, d, e) +#define TRACE6(context, event, a, b, c, d, e, f) DTRACE_PROBE6(context, event, a, b, c, d, e, f) +#define TRACE7(context, event, a, b, c, d, e, f, g) DTRACE_PROBE7(context, event, a, b, c, d, e, f, g) +#define TRACE8(context, event, a, b, c, d, e, f, g, h) DTRACE_PROBE8(context, event, a, b, c, d, e, f, g, h) +#define TRACE9(context, event, a, b, c, d, e, f, g, h, i) DTRACE_PROBE9(context, event, a, b, c, d, e, f, g, h, i) +#define TRACE10(context, event, a, b, c, d, e, f, g, h, i, j) DTRACE_PROBE10(context, event, a, b, c, d, e, f, g, h, i, j) +#define TRACE11(context, event, a, b, c, d, e, f, g, h, i, j, k) DTRACE_PROBE11(context, event, a, b, c, d, e, f, g, h, i, j, k) +#define TRACE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l) DTRACE_PROBE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l) + +#else + +#define TRACE(context, event) +#define TRACE1(context, event, a) +#define TRACE2(context, event, a, b) +#define TRACE3(context, event, a, b, c) +#define TRACE4(context, event, a, b, c, d) +#define TRACE5(context, event, a, b, c, d, e) +#define TRACE6(context, event, a, b, c, d, e, f) +#define TRACE7(context, event, a, b, c, d, e, f, g) +#define TRACE8(context, event, a, b, c, d, e, f, g, h) +#define TRACE9(context, event, a, b, c, d, e, f, g, h, i) +#define TRACE10(context, event, a, b, c, d, e, f, g, h, i, j) +#define TRACE11(context, event, a, b, c, d, e, f, g, h, i, j, k) +#define TRACE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l) + +#endif + + +#endif /* BITCOIN_UTIL_TRACE_H */ diff --git a/src/util/translation.h b/src/util/translation.h index 695d6dac96..99899ef3c2 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/validation.cpp b/src/validation.cpp index e9c0607ced..eeb99f0f0a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -22,7 +22,6 @@ #include <logging/timer.h> #include <node/ui_interface.h> #include <optional.h> -#include <policy/fees.h> #include <policy/policy.h> #include <policy/settings.h> #include <pow.h> @@ -148,8 +147,6 @@ arith_uint256 nMinimumChainWork; CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); -CBlockPolicyEstimator feeEstimator; - // Internal stuff namespace { CBlockIndex* pindexBestInvalid = nullptr; @@ -384,7 +381,7 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact TxValidationState stateDummy; if (!fAddToMempool || (*it)->IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, *it, - nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) { + nullptr /* plTxnReplaced */, true /* bypass_limits */)) { // If the transaction doesn't make it in to the mempool, remove any // transactions that depend on it (which would now be orphans). mempool.removeRecursive(**it, MemPoolRemovalReason::REORG); @@ -407,36 +404,41 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); } -// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool -// were somehow broken and returning the wrong scriptPubKeys -static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool, - unsigned int flags, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { +/** +* Checks to avoid mempool polluting consensus critical paths since cached +* signature and script validity results will be reused if we validate this +* transaction again during block validation. +* */ +static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state, + const CCoinsViewCache& view, const CTxMemPool& pool, + unsigned int flags, PrecomputedTransactionData& txdata) + EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs) +{ AssertLockHeld(cs_main); - - // pool.cs should be locked already, but go ahead and re-take the lock here - // to enforce that mempool doesn't change between when we check the view - // and when we actually call through to CheckInputScripts - LOCK(pool.cs); + AssertLockHeld(pool.cs); assert(!tx.IsCoinBase()); for (const CTxIn& txin : tx.vin) { const Coin& coin = view.AccessCoin(txin.prevout); - // AcceptToMemoryPoolWorker has already checked that the coins are - // available, so this shouldn't fail. If the inputs are not available - // here then return false. + // This coin was checked in PreChecks and MemPoolAccept + // has been holding cs_main since then. + Assume(!coin.IsSpent()); if (coin.IsSpent()) return false; - // Check equivalence for available inputs. + // If the Coin is available, there are 2 possibilities: + // it is available in our current ChainstateActive UTXO set, + // or it's a UTXO provided by a transaction in our mempool. + // Ensure the scriptPubKeys in Coins from CoinsView are correct. const CTransactionRef& txFrom = pool.get(txin.prevout.hash); if (txFrom) { assert(txFrom->GetHash() == txin.prevout.hash); assert(txFrom->vout.size() > txin.prevout.n); assert(txFrom->vout[txin.prevout.n] == coin.out); } else { - const Coin& coinFromDisk = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout); - assert(!coinFromDisk.IsSpent()); - assert(coinFromDisk.out == coin.out); + const Coin& coinFromUTXOSet = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout); + assert(!coinFromUTXOSet.IsSpent()); + assert(coinFromUTXOSet.out == coin.out); } } @@ -449,7 +451,7 @@ namespace { class MemPoolAccept { public: - MemPoolAccept(CTxMemPool& mempool) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&::ChainstateActive().CoinsTip(), m_pool), + explicit MemPoolAccept(CTxMemPool& mempool) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&::ChainstateActive().CoinsTip(), m_pool), m_limit_ancestors(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)), m_limit_ancestor_size(gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000), m_limit_descendants(gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)), @@ -463,7 +465,6 @@ public: const int64_t m_accept_time; std::list<CTransactionRef>* m_replaced_transactions; const bool m_bypass_limits; - const CAmount& m_absurd_fee; /* * Return any outpoints which were not previously present in the coins * cache, but were added as a result of validating the tx for mempool @@ -483,7 +484,7 @@ private: // All the intermediate state that gets passed between the various levels // of checking a given transaction. struct Workspace { - Workspace(const CTransactionRef& ptx) : m_ptx(ptx), m_hash(ptx->GetHash()) {} + explicit Workspace(const CTransactionRef& ptx) : m_ptx(ptx), m_hash(ptx->GetHash()) {} std::set<uint256> m_conflicts; CTxMemPool::setEntries m_all_conflicting; CTxMemPool::setEntries m_ancestors; @@ -506,13 +507,13 @@ private: // Run the script checks using our policy flags. As this can be slow, we should // only invoke this on transactions that have otherwise passed policy checks. - bool PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Re-run the script checks, using consensus flags, and try to cache the // result in the scriptcache. This should be done after // PolicyScriptChecks(). This requires that all inputs either be in our // utxo set or in the mempool. - bool ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Try to add the transaction to the mempool, removing any conflicts first. // Returns true if the transaction is in the mempool after any size @@ -520,7 +521,7 @@ private: bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Compare a package's feerate against minimum allowed. - bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) + bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs) { CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { @@ -558,7 +559,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) TxValidationState &state = args.m_state; const int64_t nAcceptTime = args.m_accept_time; const bool bypass_limits = args.m_bypass_limits; - const CAmount& nAbsurdFee = args.m_absurd_fee; std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache; // Alias what we need out of ws @@ -642,7 +642,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) LockPoints lp; m_view.SetBackend(m_viewmempool); - CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip(); + const CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip(); // do all inputs exist? for (const CTxIn& txin : tx.vin) { if (!coins_cache.HaveCoinInCache(txin.prevout)) { @@ -692,11 +692,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) } // Check for non-standard pay-to-script-hash in inputs - if (fRequireStandard && !AreInputsStandard(tx, m_view)) { + const auto& params = args.m_chainparams.GetConsensus(); + auto taproot_state = VersionBitsState(::ChainActive().Tip(), params, Consensus::DEPLOYMENT_TAPROOT, versionbitscache); + if (fRequireStandard && !AreInputsStandard(tx, m_view, taproot_state == ThresholdState::ACTIVE)) { return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs"); } - // Check for non-standard witness in P2WSH + // Check for non-standard witnesses. if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view)) return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-witness-nonstandard"); @@ -729,10 +731,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) // blocks if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false; - if (nAbsurdFee && nFees > nAbsurdFee) - return state.Invalid(TxValidationResult::TX_NOT_STANDARD, - "absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee)); - const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts); // Calculate in-mempool ancestors, up to a limit. if (setConflicts.size() == 1) { @@ -925,7 +923,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) return true; } -bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) +bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) { const CTransaction& tx = *ws.m_ptx; @@ -952,7 +950,7 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute return true; } -bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) +bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) { const CTransaction& tx = *ws.m_ptx; const uint256& hash = ws.m_hash; @@ -1065,10 +1063,10 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs /** (try to) add transaction to memory pool with a specified acceptance time **/ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced, - bool bypass_limits, const CAmount nAbsurdFee, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main) + bool bypass_limits, bool test_accept, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { std::vector<COutPoint> coins_to_uncache; - MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept, fee_out }; + MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, coins_to_uncache, test_accept, fee_out }; bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args); if (!res) { // Remove coins that were not present in the coins cache before calling ATMPW; @@ -1087,10 +1085,10 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx, std::list<CTransactionRef>* plTxnReplaced, - bool bypass_limits, const CAmount nAbsurdFee, bool test_accept, CAmount* fee_out) + bool bypass_limits, bool test_accept, CAmount* fee_out) { const CChainParams& chainparams = Params(); - return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept, fee_out); + return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, test_accept, fee_out); } CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock) @@ -1316,8 +1314,6 @@ bool CChainState::IsInitialBlockDownload() const return false; } -static CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr; - static void AlertNotify(const std::string& strMessage) { uiInterface.NotifyAlertChanged(); @@ -1343,73 +1339,16 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) AssertLockHeld(cs_main); // Before we get past initial download, we cannot reliably alert about forks // (we assume we don't get stuck on a fork before finishing our initial sync) - if (::ChainstateActive().IsInitialBlockDownload()) + if (::ChainstateActive().IsInitialBlockDownload()) { return; - - // If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it) - // of our head, drop it - if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72) - pindexBestForkTip = nullptr; - - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6))) - { - if (!GetfLargeWorkForkFound() && pindexBestForkBase) - { - std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + - pindexBestForkBase->phashBlock->ToString() + std::string("'"); - AlertNotify(warning); - } - if (pindexBestForkTip && pindexBestForkBase) - { - LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, - pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), - pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); - SetfLargeWorkForkFound(true); - } - else - { - LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); - SetfLargeWorkInvalidChainFound(true); - } - } - else - { - SetfLargeWorkForkFound(false); - SetfLargeWorkInvalidChainFound(false); } -} -static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - AssertLockHeld(cs_main); - // If we are on a fork that is sufficiently large, set a warning flag - CBlockIndex* pfork = pindexNewForkTip; - CBlockIndex* plonger = ::ChainActive().Tip(); - while (pfork && pfork != plonger) - { - while (plonger && plonger->nHeight > pfork->nHeight) - plonger = plonger->pprev; - if (pfork == plonger) - break; - pfork = pfork->pprev; - } - - // We define a condition where we should warn the user about as a fork of at least 7 blocks - // with a tip within 72 blocks (+/- 12 hours if no one mines it) of ours - // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network - // hash rate operating on the fork. - // or a chain that is entirely longer than ours and invalid (note that this should be detected by both) - // We define it this way because it allows us to only store the highest fork tip (+ base) which meets - // the 7-block condition and from this always have the most-likely-to-cause-warning fork - if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) && - pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && - ::ChainActive().Height() - pindexNewForkTip->nHeight < 72) - { - pindexBestForkTip = pindexNewForkTip; - pindexBestForkBase = pfork; + if (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6)) { + LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); + SetfLargeWorkInvalidChainFound(true); + } else { + SetfLargeWorkInvalidChainFound(false); } - - CheckForkWarningConditions(); } // Called both upon regular invalid block discovery *and* InvalidateBlock @@ -1538,14 +1477,21 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C return true; } - if (!txdata.m_ready) { - txdata.Init(tx); + if (!txdata.m_spent_outputs_ready) { + std::vector<CTxOut> spent_outputs; + spent_outputs.reserve(tx.vin.size()); + + for (const auto& txin : tx.vin) { + const COutPoint& prevout = txin.prevout; + const Coin& coin = inputs.AccessCoin(prevout); + assert(!coin.IsSpent()); + spent_outputs.emplace_back(coin.out); + } + txdata.Init(tx, std::move(spent_outputs)); } + assert(txdata.m_spent_outputs.size() == tx.vin.size()); for (unsigned int i = 0; i < tx.vin.size(); i++) { - const COutPoint &prevout = tx.vin[i].prevout; - const Coin& coin = inputs.AccessCoin(prevout); - assert(!coin.IsSpent()); // We very carefully only pass in things to CScriptCheck which // are clearly committed to by tx' witness hash. This provides @@ -1554,7 +1500,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C // spent being checked as a part of CScriptCheck. // Verify signature - CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata); + CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata); if (pvChecks) { pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); @@ -1568,7 +1514,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C // splitting the network between upgraded and // non-upgraded nodes by banning CONSENSUS-failing // data providers. - CScriptCheck check2(coin.out, tx, i, + CScriptCheck check2(txdata.m_spent_outputs[i], tx, i, flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata); if (check2()) return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); @@ -1817,9 +1763,14 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationSt static CCheckQueue<CScriptCheck> scriptcheckqueue(128); -void ThreadScriptCheck(int worker_num) { - util::ThreadRename(strprintf("scriptch.%i", worker_num)); - scriptcheckqueue.Thread(); +void StartScriptCheckWorkerThreads(int threads_num) +{ + scriptcheckqueue.StartWorkerThreads(threads_num); +} + +void StopScriptCheckWorkerThreads() +{ + scriptcheckqueue.StopWorkerThreads(); } VersionBitsCache versionbitscache GUARDED_BY(cs_main); @@ -1913,6 +1864,11 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; } + // Start enforcing Taproot using versionbits logic. + if (VersionBitsState(pindex->pprev, consensusparams, Consensus::DEPLOYMENT_TAPROOT, versionbitscache) == ThresholdState::ACTIVE) { + flags |= SCRIPT_VERIFY_TAPROOT; + } + // Start enforcing BIP147 NULLDUMMY (activated simultaneously with segwit) if (IsWitnessEnabled(pindex->pprev, consensusparams)) { flags |= SCRIPT_VERIFY_NULLDUMMY; @@ -2449,9 +2405,7 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C } bilingual_str warning_messages; - int num_unexpected_version = 0; - if (!::ChainstateActive().IsInitialBlockDownload()) - { + if (!::ChainstateActive().IsInitialBlockDownload()) { const CBlockIndex* pindex = pindexNew; for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { WarningBitsConditionChecker checker(bit); @@ -2465,14 +2419,6 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C } } } - // Check the version of the last 100 blocks to see if we need to upgrade: - for (int i = 0; i < 100 && pindex != nullptr; i++) - { - int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); - if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0) - ++num_unexpected_version; - pindex = pindex->pprev; - } } LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n", __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion, @@ -2480,10 +2426,6 @@ static void UpdateTip(CTxMemPool& mempool, const CBlockIndex* pindexNew, const C FormatISO8601DateTime(pindexNew->GetBlockTime()), GuessVerificationProgress(chainParams.TxData(), pindexNew), ::ChainstateActive().CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), ::ChainstateActive().CoinsTip().GetCacheSize(), !warning_messages.empty() ? strprintf(" warning='%s'", warning_messages.original) : ""); - - if (num_unexpected_version > 0) { - LogPrint(BCLog::VALIDATION, "%d of last 100 blocks have unexpected version\n", num_unexpected_version); - } } /** Disconnect m_chain's tip. @@ -2738,8 +2680,8 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai AssertLockHeld(cs_main); AssertLockHeld(m_mempool.cs); - const CBlockIndex *pindexOldTip = m_chain.Tip(); - const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork); + const CBlockIndex* pindexOldTip = m_chain.Tip(); + const CBlockIndex* pindexFork = m_chain.FindFork(pindexMostWork); // Disconnect active blocks which are no longer in the best chain. bool fBlocksDisconnected = false; @@ -2759,7 +2701,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai fBlocksDisconnected = true; } - // Build list of new blocks to connect. + // Build list of new blocks to connect (in descending height order). std::vector<CBlockIndex*> vpindexToConnect; bool fContinue = true; int nHeight = pindexFork ? pindexFork->nHeight : -1; @@ -2769,7 +2711,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); vpindexToConnect.clear(); vpindexToConnect.reserve(nTargetHeight - nHeight); - CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); + CBlockIndex* pindexIter = pindexMostWork->GetAncestor(nTargetHeight); while (pindexIter && pindexIter->nHeight != nHeight) { vpindexToConnect.push_back(pindexIter); pindexIter = pindexIter->pprev; @@ -2777,7 +2719,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai nHeight = nTargetHeight; // Connect new blocks. - for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) { + for (CBlockIndex* pindexConnect : reverse_iterate(vpindexToConnect)) { if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) { if (state.IsInvalid()) { // The block violates a consensus rule. @@ -2813,11 +2755,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai } m_mempool.check(&CoinsTip()); - // Callbacks/notifications for a new best chain. - if (fInvalidFound) - CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); - else - CheckForkWarningConditions(); + CheckForkWarningConditions(); return true; } @@ -5076,10 +5014,10 @@ bool LoadMempool(CTxMemPool& pool) pool.PrioritiseTransaction(tx->GetHash(), amountdelta); } TxValidationState state; - if (nTime + nExpiryTimeout > nNow) { + if (nTime > nNow - nExpiryTimeout) { LOCK(cs_main); AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nTime, - nullptr /* plTxnReplaced */, false /* bypass_limits */, 0 /* nAbsurdFee */, + nullptr /* plTxnReplaced */, false /* bypass_limits */, false /* test_accept */); if (state.IsValid()) { ++count; @@ -5107,15 +5045,9 @@ bool LoadMempool(CTxMemPool& pool) pool.PrioritiseTransaction(i.first, i.second); } - // TODO: remove this try except in v0.22 std::set<uint256> unbroadcast_txids; - try { - file >> unbroadcast_txids; - unbroadcast = unbroadcast_txids.size(); - } catch (const std::exception&) { - // mempool.dat files created prior to v0.21 will not have an - // unbroadcast set. No need to log a failure if parsing fails here. - } + file >> unbroadcast_txids; + unbroadcast = unbroadcast_txids.size(); for (const auto& txid : unbroadcast_txids) { // Ensure transactions were accepted to mempool then add to // unbroadcast set. @@ -5179,7 +5111,9 @@ bool DumpMempool(const CTxMemPool& pool) if (!FileCommit(file.Get())) throw std::runtime_error("FileCommit failed"); file.fclose(); - RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat"); + if (!RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat")) { + throw std::runtime_error("Rename failed"); + } int64_t last = GetTimeMicros(); LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*MICRO, (last-mid)*MICRO); } catch (const std::exception& e) { diff --git a/src/validation.h b/src/validation.h index d88bd07765..d3fbabe1a2 100644 --- a/src/validation.h +++ b/src/validation.h @@ -23,6 +23,7 @@ #include <txdb.h> #include <versionbits.h> #include <serialize.h> +#include <util/hasher.h> #include <atomic> #include <map> @@ -42,7 +43,6 @@ class CChainParams; class CInv; class CConnman; class CScriptCheck; -class CBlockPolicyEstimator; class CTxMemPool; class ChainstateManager; class TxValidationState; @@ -94,14 +94,6 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3; // 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; -struct BlockHasher -{ - // this used to call `GetCheapHash()` in uint256, which was later moved; the - // cheap hash function simply calls ReadLE64() however, so the end result is - // identical - size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); } -}; - /** Current sync state passed to tip changed callbacks. */ enum class SynchronizationState { INIT_REINDEX, @@ -110,7 +102,6 @@ enum class SynchronizationState { }; extern RecursiveMutex cs_main; -extern CBlockPolicyEstimator feeEstimator; typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; extern Mutex g_best_block_mutex; extern std::condition_variable g_best_block_cv; @@ -158,8 +149,10 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi bool LoadGenesisBlock(const CChainParams& chainparams); /** Unload database information */ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman); -/** Run an instance of the script checking thread */ -void ThreadScriptCheck(int worker_num); +/** Run instances of script checking worker threads */ +void StartScriptCheckWorkerThreads(int threads_num); +/** Stop all of the script checking worker threads */ +void StopScriptCheckWorkerThreads(); /** * Return transaction from the block at block_index. * If block_index is not provided, fall back to mempool. @@ -201,7 +194,7 @@ void PruneBlockFilesManual(int nManualPruneHeight); * @param[out] fee_out optional argument to return tx fee to the caller **/ bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx, std::list<CTransactionRef>* plTxnReplaced, - bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool bypass_limits, bool test_accept=false, CAmount* fee_out=nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Get the BIP9 state for a given deployment at the current tip. */ ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos); @@ -503,9 +496,9 @@ enum class CoinsCacheSizeState * whereas block information and metadata independent of the current tip is * kept in `BlockMetadataManager`. */ -class CChainState { -private: - +class CChainState +{ +protected: /** * Every received block is assigned a unique and increasing identifier, so we * know which one to give priority in case of a fork. @@ -564,7 +557,7 @@ public: //! @returns whether or not the CoinsViews object has been fully initialized and we can //! safely flush this object to disk. - bool CanFlushToDisk() EXCLUSIVE_LOCKS_REQUIRED(cs_main) { + bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return m_coins_views && m_coins_views->m_cacheview; } diff --git a/src/version.h b/src/version.h index 019c3a3ae7..ee646eefc3 100644 --- a/src/version.h +++ b/src/version.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2018 The Bitcoin Core developers +// Copyright (c) 2012-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp index 20297b9f9d..fa41bad46d 100644 --- a/src/versionbitsinfo.cpp +++ b/src/versionbitsinfo.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,4 +11,8 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.name =*/ "testdummy", /*.gbt_force =*/ true, }, + { + /*.name =*/ "taproot", + /*.gbt_force =*/ true, + }, }; diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index fbb3d2cac5..c0d107bf39 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -53,16 +53,13 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const } /** - * @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. + * @param[in] env_directory Path to environment 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) +std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory) { - fs::path env_directory; - SplitWalletPath(wallet_path, env_directory, database_filename); LOCK(cs_db); auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>()); if (inserted.second) { @@ -305,17 +302,16 @@ BerkeleyDatabase::~BerkeleyDatabase() } } -BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr), m_database(database) +BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const bool read_only, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr), m_database(database) { database.AddRef(); - database.Open(pszMode); - fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); + database.Open(); + fReadOnly = read_only; fFlushOnClose = fFlushOnCloseIn; env = database.env.get(); pdb = database.m_db.get(); strFile = database.strFile; - bool fCreate = strchr(pszMode, 'c') != nullptr; - if (fCreate && !Exists(std::string("version"))) { + if (!Exists(std::string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; Write(std::string("version"), CLIENT_VERSION); @@ -323,12 +319,9 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo } } -void BerkeleyDatabase::Open(const char* pszMode) +void BerkeleyDatabase::Open() { - bool fCreate = strchr(pszMode, 'c') != nullptr; - unsigned int nFlags = DB_THREAD; - if (fCreate) - nFlags |= DB_CREATE; + unsigned int nFlags = DB_THREAD | DB_CREATE; { LOCK(cs_db); @@ -468,7 +461,7 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip) LogPrintf("BerkeleyBatch::Rewrite: Rewriting %s...\n", strFile); std::string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} - BerkeleyBatch db(*this, "r"); + BerkeleyBatch db(*this, true); std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0); int ret = pdbCopy->open(nullptr, // Txn pointer @@ -730,6 +723,23 @@ bool BerkeleyBatch::TxnAbort() return (ret == 0); } +bool BerkeleyDatabaseSanityCheck() +{ + int major, minor; + DbEnv::version(&major, &minor, nullptr); + + /* If the major version differs, or the minor version of library is *older* + * than the header that was compiled against, flag an error. + */ + if (major != DB_VERSION_MAJOR || minor < DB_VERSION_MINOR) { + LogPrintf("BerkeleyDB database version conflict: header version is %d.%d, library version is %d.%d\n", + DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor); + return false; + } + + return true; +} + std::string BerkeleyDatabaseVersion() { return DbEnv::version(nullptr, nullptr, nullptr); @@ -807,26 +817,19 @@ void BerkeleyDatabase::RemoveRef() if (env) env->m_db_in_use.notify_all(); } -std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(const char* mode, bool flush_on_close) -{ - return MakeUnique<BerkeleyBatch>(*this, mode, flush_on_close); -} - -bool ExistsBerkeleyDatabase(const fs::path& path) +std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(bool flush_on_close) { - fs::path env_directory; - std::string data_filename; - SplitWalletPath(path, env_directory, data_filename); - return IsBerkeleyBtree(env_directory / data_filename); + return MakeUnique<BerkeleyBatch>(*this, false, flush_on_close); } std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) { + fs::path data_file = BDBDataFile(path); std::unique_ptr<BerkeleyDatabase> db; { LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor - std::string data_filename; - std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(path, data_filename); + std::string data_filename = data_file.filename().string(); + std::shared_ptr<BerkeleyEnvironment> env = GetBerkeleyEnv(data_file.parent_path()); if (env->m_databases.count(data_filename)) { error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string())); status = DatabaseStatus::FAILED_ALREADY_LOADED; diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index fd5a49acc3..a8209587d7 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -56,7 +56,7 @@ public: std::unordered_map<std::string, WalletDatabaseFileId> m_fileids; std::condition_variable_any m_db_in_use; - BerkeleyEnvironment(const fs::path& env_directory); + explicit BerkeleyEnvironment(const fs::path& env_directory); BerkeleyEnvironment(); ~BerkeleyEnvironment(); void Reset(); @@ -83,11 +83,8 @@ public: } }; -/** Get BerkeleyEnvironment and database filename given a wallet path. */ -std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename); - -/** Check format of database file */ -bool IsBerkeleyBtree(const fs::path& path); +/** Get BerkeleyEnvironment given a directory path. */ +std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory); class BerkeleyBatch; @@ -109,9 +106,8 @@ public: ~BerkeleyDatabase() override; - /** Open the database if it is not already opened. - * Dummy function, doesn't do anything right now, but is needed for class abstraction */ - void Open(const char* mode) override; + /** Open the database if it is not already opened. */ + void Open() override; /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero */ @@ -147,6 +143,7 @@ public: /** Return path to main database filename */ std::string Filename() override { return (env->Directory() / strFile).string(); } + std::string Format() override { return "bdb"; } /** * Pointer to shared database environment. * @@ -164,7 +161,7 @@ public: std::string strFile; /** Make a BerkeleyBatch connected to this database */ - std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override; + std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override; }; /** RAII class that provides access to a Berkeley database */ @@ -207,7 +204,7 @@ protected: BerkeleyDatabase& m_database; public: - explicit BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode = "r+", bool fFlushOnCloseIn=true); + explicit BerkeleyBatch(BerkeleyDatabase& database, const bool fReadOnly, bool fFlushOnCloseIn=true); ~BerkeleyBatch() override; BerkeleyBatch(const BerkeleyBatch&) = delete; @@ -226,8 +223,9 @@ public: std::string BerkeleyDatabaseVersion(); -//! Check if Berkeley database exists at specified path. -bool ExistsBerkeleyDatabase(const fs::path& path); +/** Perform sanity check of runtime BDB version versus linked BDB version. + */ +bool BerkeleyDatabaseSanityCheck(); //! Return object giving access to Berkeley database at specified path. std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp index 8032deb2fa..10f89e3a6f 100644 --- a/src/wallet/coinselection.cpp +++ b/src/wallet/coinselection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index 5d9a410dce..f0e1addaf1 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index f2df786e2e..f7325541a9 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index bd1d114730..cd49baeb78 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -3,23 +3,130 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <chainparams.h> #include <fs.h> +#include <logging.h> #include <wallet/db.h> #include <string> -void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename) +std::vector<fs::path> ListDatabases(const fs::path& wallet_dir) +{ + const size_t offset = wallet_dir.string().size() + 1; + std::vector<fs::path> paths; + boost::system::error_code ec; + + for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) { + if (ec) { + LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string()); + continue; + } + + try { + // Get wallet path relative to walletdir by removing walletdir from the wallet path. + // This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60. + const fs::path path = it->path().string().substr(offset); + + if (it->status().type() == fs::directory_file && + (IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) { + // Found a directory which contains wallet.dat btree file, add it as a wallet. + paths.emplace_back(path); + } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBDBFile(it->path())) { + if (it->path().filename() == "wallet.dat") { + // Found top-level wallet.dat btree file, add top level directory "" + // as a wallet. + paths.emplace_back(); + } else { + // Found top-level btree file not called wallet.dat. Current bitcoin + // software will never create these files but will allow them to be + // opened in a shared database environment for backwards compatibility. + // Add it to the list of available wallets. + paths.emplace_back(path); + } + } + } catch (const std::exception& e) { + LogPrintf("%s: Error scanning %s: %s\n", __func__, it->path().string(), e.what()); + it.no_push(); + } + } + + return paths; +} + +fs::path BDBDataFile(const fs::path& wallet_path) { if (fs::is_regular_file(wallet_path)) { // Special case for backwards compatibility: if wallet path points to an // existing file, treat it as the path to a BDB data file in a parent // directory that also contains BDB log files. - env_directory = wallet_path.parent_path(); - database_filename = wallet_path.filename().string(); + return wallet_path; } else { // Normal case: Interpret wallet path as a directory path containing // data and log files. - env_directory = wallet_path; - database_filename = "wallet.dat"; + return wallet_path / "wallet.dat"; } } + +fs::path SQLiteDataFile(const fs::path& path) +{ + return path / "wallet.dat"; +} + +bool IsBDBFile(const fs::path& path) +{ + if (!fs::exists(path)) return false; + + // A Berkeley DB Btree file has at least 4K. + // This check also prevents opening lock files. + boost::system::error_code ec; + auto size = fs::file_size(path, ec); + if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string()); + if (size < 4096) return false; + + fsbridge::ifstream file(path, std::ios::binary); + if (!file.is_open()) return false; + + file.seekg(12, std::ios::beg); // Magic bytes start at offset 12 + uint32_t data = 0; + file.read((char*) &data, sizeof(data)); // Read 4 bytes of file to compare against magic + + // Berkeley DB Btree magic bytes, from: + // https://github.com/file/file/blob/5824af38469ec1ca9ac3ffd251e7afe9dc11e227/magic/Magdir/database#L74-L75 + // - big endian systems - 00 05 31 62 + // - little endian systems - 62 31 05 00 + return data == 0x00053162 || data == 0x62310500; +} + +bool IsSQLiteFile(const fs::path& path) +{ + if (!fs::exists(path)) return false; + + // A SQLite Database file is at least 512 bytes. + boost::system::error_code ec; + auto size = fs::file_size(path, ec); + if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string()); + if (size < 512) return false; + + fsbridge::ifstream file(path, std::ios::binary); + if (!file.is_open()) return false; + + // Magic is at beginning and is 16 bytes long + char magic[16]; + file.read(magic, 16); + + // Application id is at offset 68 and 4 bytes long + file.seekg(68, std::ios::beg); + char app_id[4]; + file.read(app_id, 4); + + file.close(); + + // Check the magic, see https://sqlite.org/fileformat2.html + std::string magic_str(magic, 16); + if (magic_str != std::string("SQLite format 3", 16)) { + return false; + } + + // Check the application id matches our network magic + return memcmp(Params().MessageStart(), app_id, 4) == 0; +} diff --git a/src/wallet/db.h b/src/wallet/db.h index 617ed46141..2c75486a44 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -8,6 +8,7 @@ #include <clientversion.h> #include <fs.h> +#include <optional.h> #include <streams.h> #include <support/allocators/secure.h> #include <util/memory.h> @@ -108,7 +109,7 @@ public: virtual ~WalletDatabase() {}; /** Open the database if it is not already opened. */ - virtual void Open(const char* mode) = 0; + virtual void Open() = 0; //! Counts the number of active database users to be sure that the database is not closed while someone is using it std::atomic<int> m_refcount{0}; @@ -143,13 +144,15 @@ public: /** Return path to main database file for logs and error messages. */ virtual std::string Filename() = 0; + virtual std::string Format() = 0; + std::atomic<unsigned int> nUpdateCounter; unsigned int nLastSeen; unsigned int nLastFlushed; int64_t nLastWalletUpdate; /** Make a DatabaseBatch connected to this database */ - virtual std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) = 0; + virtual std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) = 0; }; /** RAII class that provides access to a DummyDatabase. Never fails. */ @@ -178,7 +181,7 @@ public: class DummyDatabase : public WalletDatabase { public: - void Open(const char* mode) override {}; + void Open() override {}; void AddRef() override {} void RemoveRef() override {} bool Rewrite(const char* pszSkip=nullptr) override { return true; } @@ -189,16 +192,19 @@ public: void IncrementUpdateCounter() override { ++nUpdateCounter; } void ReloadDbEnv() override {} std::string Filename() override { return "dummy"; } - std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); } + std::string Format() override { return "dummy"; } + std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); } }; enum class DatabaseFormat { BERKELEY, + SQLITE, }; struct DatabaseOptions { bool require_existing = false; bool require_create = false; + Optional<DatabaseFormat> require_format; uint64_t create_flags = 0; SecureString create_passphrase; bool verify = true; @@ -217,6 +223,14 @@ enum class DatabaseStatus { FAILED_ENCRYPT, }; +/** Recursively list database paths in directory. */ +std::vector<fs::path> ListDatabases(const fs::path& path); + std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); +fs::path BDBDataFile(const fs::path& path); +fs::path SQLiteDataFile(const fs::path& path); +bool IsBDBFile(const fs::path& path); +bool IsSQLiteFile(const fs::path& path); + #endif // BITCOIN_WALLET_DB_H diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp new file mode 100644 index 0000000000..e314107988 --- /dev/null +++ b/src/wallet/dump.cpp @@ -0,0 +1,282 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <wallet/dump.h> + +#include <util/translation.h> +#include <wallet/wallet.h> + +static const std::string DUMP_MAGIC = "BITCOIN_CORE_WALLET_DUMP"; +uint32_t DUMP_VERSION = 1; + +bool DumpWallet(CWallet& wallet, bilingual_str& error) +{ + // Get the dumpfile + std::string dump_filename = gArgs.GetArg("-dumpfile", ""); + if (dump_filename.empty()) { + error = _("No dump file provided. To use dump, -dumpfile=<filename> must be provided."); + return false; + } + + fs::path path = dump_filename; + path = fs::absolute(path); + if (fs::exists(path)) { + error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), path.string()); + return false; + } + fsbridge::ofstream dump_file; + dump_file.open(path); + if (dump_file.fail()) { + error = strprintf(_("Unable to open %s for writing"), path.string()); + return false; + } + + CHashWriter hasher(0, 0); + + WalletDatabase& db = wallet.GetDatabase(); + std::unique_ptr<DatabaseBatch> batch = db.MakeBatch(); + + bool ret = true; + if (!batch->StartCursor()) { + error = _("Error: Couldn't create cursor into database"); + ret = false; + } + + // Write out a magic string with version + std::string line = strprintf("%s,%u\n", DUMP_MAGIC, DUMP_VERSION); + dump_file.write(line.data(), line.size()); + hasher.write(line.data(), line.size()); + + // Write out the file format + line = strprintf("%s,%s\n", "format", db.Format()); + dump_file.write(line.data(), line.size()); + hasher.write(line.data(), line.size()); + + if (ret) { + + // Read the records + while (true) { + CDataStream ss_key(SER_DISK, CLIENT_VERSION); + CDataStream ss_value(SER_DISK, CLIENT_VERSION); + bool complete; + ret = batch->ReadAtCursor(ss_key, ss_value, complete); + if (complete) { + ret = true; + break; + } else if (!ret) { + error = _("Error reading next record from wallet database"); + break; + } + std::string key_str = HexStr(ss_key); + std::string value_str = HexStr(ss_value); + line = strprintf("%s,%s\n", key_str, value_str); + dump_file.write(line.data(), line.size()); + hasher.write(line.data(), line.size()); + } + } + + batch->CloseCursor(); + batch.reset(); + + // Close the wallet after we're done with it. The caller won't be doing this + wallet.Close(); + + if (ret) { + // Write the hash + tfm::format(dump_file, "checksum,%s\n", HexStr(hasher.GetHash())); + dump_file.close(); + } else { + // Remove the dumpfile on failure + dump_file.close(); + fs::remove(path); + } + + return ret; +} + +// 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->Close(); + delete wallet; +} + +bool CreateFromDump(const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings) +{ + // Get the dumpfile + std::string dump_filename = gArgs.GetArg("-dumpfile", ""); + if (dump_filename.empty()) { + error = _("No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided."); + return false; + } + + fs::path dump_path = dump_filename; + dump_path = fs::absolute(dump_path); + if (!fs::exists(dump_path)) { + error = strprintf(_("Dump file %s does not exist."), dump_path.string()); + return false; + } + fsbridge::ifstream dump_file(dump_path); + + // Compute the checksum + CHashWriter hasher(0, 0); + uint256 checksum; + + // Check the magic and version + std::string magic_key; + std::getline(dump_file, magic_key, ','); + std::string version_value; + std::getline(dump_file, version_value, '\n'); + if (magic_key != DUMP_MAGIC) { + error = strprintf(_("Error: Dumpfile identifier record is incorrect. Got \"%s\", expected \"%s\"."), magic_key, DUMP_MAGIC); + dump_file.close(); + return false; + } + // Check the version number (value of first record) + uint32_t ver; + if (!ParseUInt32(version_value, &ver)) { + error =strprintf(_("Error: Unable to parse version %u as a uint32_t"), version_value); + dump_file.close(); + return false; + } + if (ver != DUMP_VERSION) { + error = strprintf(_("Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s"), version_value); + dump_file.close(); + return false; + } + std::string magic_hasher_line = strprintf("%s,%s\n", magic_key, version_value); + hasher.write(magic_hasher_line.data(), magic_hasher_line.size()); + + // Get the stored file format + std::string format_key; + std::getline(dump_file, format_key, ','); + std::string format_value; + std::getline(dump_file, format_value, '\n'); + if (format_key != "format") { + error = strprintf(_("Error: Dumpfile format record is incorrect. Got \"%s\", expected \"format\"."), format_key); + dump_file.close(); + return false; + } + // Get the data file format with format_value as the default + std::string file_format = gArgs.GetArg("-format", format_value); + if (file_format.empty()) { + error = _("No wallet file format provided. To use createfromdump, -format=<format> must be provided."); + return false; + } + DatabaseFormat data_format; + if (file_format == "bdb") { + data_format = DatabaseFormat::BERKELEY; + } else if (file_format == "sqlite") { + data_format = DatabaseFormat::SQLITE; + } else { + error = strprintf(_("Unknown wallet file format \"%s\" provided. Please provide one of \"bdb\" or \"sqlite\"."), file_format); + return false; + } + if (file_format != format_value) { + warnings.push_back(strprintf(_("Warning: Dumpfile wallet format \"%s\" does not match command line specified format \"%s\"."), format_value, file_format)); + } + std::string format_hasher_line = strprintf("%s,%s\n", format_key, format_value); + hasher.write(format_hasher_line.data(), format_hasher_line.size()); + + DatabaseOptions options; + DatabaseStatus status; + options.require_create = true; + options.require_format = data_format; + std::unique_ptr<WalletDatabase> database = MakeDatabase(wallet_path, options, status, error); + if (!database) return false; + + // dummy chain interface + bool ret = true; + std::shared_ptr<CWallet> wallet(new CWallet(nullptr /* chain */, name, std::move(database)), WalletToolReleaseWallet); + { + LOCK(wallet->cs_wallet); + bool first_run = true; + DBErrors load_wallet_ret = wallet->LoadWallet(first_run); + if (load_wallet_ret != DBErrors::LOAD_OK) { + error = strprintf(_("Error creating %s"), name); + return false; + } + + // Get the database handle + WalletDatabase& db = wallet->GetDatabase(); + std::unique_ptr<DatabaseBatch> batch = db.MakeBatch(); + batch->TxnBegin(); + + // Read the records from the dump file and write them to the database + while (dump_file.good()) { + std::string key; + std::getline(dump_file, key, ','); + std::string value; + std::getline(dump_file, value, '\n'); + + if (key == "checksum") { + std::vector<unsigned char> parsed_checksum = ParseHex(value); + std::copy(parsed_checksum.begin(), parsed_checksum.end(), checksum.begin()); + break; + } + + std::string line = strprintf("%s,%s\n", key, value); + hasher.write(line.data(), line.size()); + + if (key.empty() || value.empty()) { + continue; + } + + if (!IsHex(key)) { + error = strprintf(_("Error: Got key that was not hex: %s"), key); + ret = false; + break; + } + if (!IsHex(value)) { + error = strprintf(_("Error: Got value that was not hex: %s"), value); + ret = false; + break; + } + + std::vector<unsigned char> k = ParseHex(key); + std::vector<unsigned char> v = ParseHex(value); + + CDataStream ss_key(k, SER_DISK, CLIENT_VERSION); + CDataStream ss_value(v, SER_DISK, CLIENT_VERSION); + + if (!batch->Write(ss_key, ss_value)) { + error = strprintf(_("Error: Unable to write record to new wallet")); + ret = false; + break; + } + } + + if (ret) { + uint256 comp_checksum = hasher.GetHash(); + if (checksum.IsNull()) { + error = _("Error: Missing checksum"); + ret = false; + } else if (checksum != comp_checksum) { + error = strprintf(_("Error: Dumpfile checksum does not match. Computed %s, expected %s"), HexStr(comp_checksum), HexStr(checksum)); + ret = false; + } + } + + if (ret) { + batch->TxnCommit(); + } else { + batch->TxnAbort(); + } + + batch.reset(); + + dump_file.close(); + } + wallet.reset(); // The pointer deleter will close the wallet for us. + + // Remove the wallet dir if we have a failure + if (!ret) { + fs::remove_all(wallet_path); + } + + return ret; +} diff --git a/src/wallet/dump.h b/src/wallet/dump.h new file mode 100644 index 0000000000..d0a4f5ef1d --- /dev/null +++ b/src/wallet/dump.h @@ -0,0 +1,17 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_DUMP_H +#define BITCOIN_WALLET_DUMP_H + +#include <fs.h> + +class CWallet; + +struct bilingual_str; + +bool DumpWallet(CWallet& wallet, bilingual_str& error); +bool CreateFromDump(const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings); + +#endif // BITCOIN_WALLET_DUMP_H diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index cacf306891..5e319d4f95 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -111,7 +111,7 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt return feebumper::Result::OK; } -static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CAmount old_fee, CCoinControl& coin_control) +static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CAmount old_fee, const CCoinControl& coin_control) { // Get the fee rate of the original transaction. This is calculated from // the tx fee/vsize, so it may have been rounded down. Add 1 satoshi to the @@ -215,11 +215,12 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo // We cannot source new unconfirmed inputs(bip125 rule 2) new_coin_control.m_min_depth = 1; - CTransactionRef tx_new = MakeTransactionRef(); + CTransactionRef tx_new; CAmount fee_ret; int change_pos_in_out = -1; // No requested location for change bilingual_str fail_reason; - if (!wallet.CreateTransaction(recipients, tx_new, fee_ret, change_pos_in_out, fail_reason, new_coin_control, false)) { + FeeCalculation fee_calc_out; + if (!wallet.CreateTransaction(recipients, tx_new, fee_ret, change_pos_in_out, fail_reason, new_coin_control, fee_calc_out, false)) { errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + fail_reason); return Result::WALLET_ERROR; } @@ -230,7 +231,7 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo // Write back transaction mtx = CMutableTransaction(*tx_new); // Mark new tx not replaceable, if requested. - if (!coin_control.m_signal_bip125_rbf.get_value_or(wallet.m_signal_rbf)) { + if (!coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf)) { for (auto& input : mtx.vin) { if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe; } @@ -255,7 +256,7 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti errors.push_back(Untranslated("Invalid or non-wallet transaction id")); return Result::MISC_ERROR; } - CWalletTx& oldWtx = it->second; + const CWalletTx& oldWtx = it->second; // make sure the transaction still has no descendants and hasn't been mined in the meantime Result result = PreconditionChecks(wallet, oldWtx, errors); diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index 249bc833c6..429101e774 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -49,7 +49,7 @@ CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_contr // We will use smart fee estimation unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : wallet.m_confirm_target; // By default estimates are economical iff we are signaling opt-in-RBF - bool conservative_estimate = !coin_control.m_signal_bip125_rbf.get_value_or(wallet.m_signal_rbf); + bool conservative_estimate = !coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf); // Allow to override the default fee estimate mode over the CoinControl instance if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true; else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false; diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 5d8c4fba29..0d2be64dfb 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -15,6 +15,9 @@ #include <util/moneystr.h> #include <util/system.h> #include <util/translation.h> +#ifdef USE_BDB +#include <wallet/bdb.h> +#endif #include <wallet/coincontrol.h> #include <wallet/wallet.h> #include <walletinitinterface.h> @@ -60,7 +63,7 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const argsman.AddArg("-rescan", "Rescan the block chain for missing wallet transactions on startup", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); - argsman.AddArg("-wallet=<path>", "Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); + argsman.AddArg("-wallet=<path>", "Specify wallet path to load at startup. Can be used multiple times to load multiple wallets. Path is to a directory containing wallet data and log files. If the path is not absolute, it is interpreted relative to <walletdir>. This only loads existing wallets and does not create new ones. For backwards compatibility this also accepts names of existing top-level data files in <walletdir>.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); #if HAVE_SYSTEM @@ -68,9 +71,14 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const #endif argsman.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); +#ifdef USE_BDB argsman.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); argsman.AddArg("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); argsman.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); +#else + argsman.AddHiddenArgs({"-dblogsize", "-flushwallet", "-privdb"}); +#endif + argsman.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate mempool chain limits (default: %u)", DEFAULT_WALLET_REJECT_LONG_CHAINS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); argsman.AddHiddenArgs({"-zapwallettxes"}); @@ -78,6 +86,11 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const bool WalletInit::ParameterInteraction() const { +#ifdef USE_BDB + if (!BerkeleyDatabaseSanityCheck()) { + return InitError(Untranslated("A version conflict was detected between the run-time BerkeleyDB library and the one used during compilation.")); + } +#endif if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { for (const std::string& wallet : gArgs.GetArgs("-wallet")) { LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__, wallet); diff --git a/src/interfaces/wallet.cpp b/src/wallet/interfaces.cpp index 94c63da84e..e4e8c50f4f 100644 --- a/src/interfaces/wallet.cpp +++ b/src/wallet/interfaces.cpp @@ -31,9 +31,22 @@ #include <utility> #include <vector> -namespace interfaces { -namespace { +using interfaces::Chain; +using interfaces::FoundBlock; +using interfaces::Handler; +using interfaces::MakeHandler; +using interfaces::Wallet; +using interfaces::WalletAddress; +using interfaces::WalletBalances; +using interfaces::WalletClient; +using interfaces::WalletOrderForm; +using interfaces::WalletTx; +using interfaces::WalletTxOut; +using interfaces::WalletTxStatus; +using interfaces::WalletValueMap; +namespace wallet { +namespace { //! Construct wallet tx struct. WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) { @@ -64,7 +77,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) } //! Construct wallet tx status struct. -WalletTxStatus MakeWalletTxStatus(CWallet& wallet, const CWalletTx& wtx) +WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx) { WalletTxStatus result; result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max(); @@ -81,7 +94,7 @@ WalletTxStatus MakeWalletTxStatus(CWallet& wallet, const CWalletTx& wtx) } //! Construct wallet TxOut struct. -WalletTxOut MakeWalletTxOut(CWallet& wallet, +WalletTxOut MakeWalletTxOut(const CWallet& wallet, const CWalletTx& wtx, int n, int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) @@ -231,8 +244,9 @@ public: { LOCK(m_wallet->cs_wallet); CTransactionRef tx; + FeeCalculation fee_calc_out; if (!m_wallet->CreateTransaction(recipients, tx, fee, change_pos, - fail_reason, coin_control, sign)) { + fail_reason, coin_control, fee_calc_out, sign)) { return {}; } return tx; @@ -537,7 +551,7 @@ public: std::vector<std::string> listWalletDir() override { std::vector<std::string> paths; - for (auto& path : ListWalletDir()) { + for (auto& path : ListDatabases(GetWalletDir())) { paths.push_back(path.string()); } return paths; @@ -560,14 +574,14 @@ public: std::vector<std::unique_ptr<Handler>> m_rpc_handlers; std::list<CRPCCommand> m_rpc_commands; }; - } // namespace +} // namespace wallet -std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<WalletImpl>(wallet) : nullptr; } +namespace interfaces { +std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? MakeUnique<wallet::WalletImpl>(wallet) : nullptr; } std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args) { - return MakeUnique<WalletClientImpl>(chain, args); + return MakeUnique<wallet::WalletClientImpl>(chain, args); } - } // namespace interfaces diff --git a/src/wallet/ismine.h b/src/wallet/ismine.h index 5cdd7dff80..38ed7e7770 100644 --- a/src/wallet/ismine.h +++ b/src/wallet/ismine.h @@ -14,7 +14,27 @@ class CWallet; class CScript; -/** IsMine() return codes */ +/** + * IsMine() return codes, which depend on ScriptPubKeyMan implementation. + * Not every ScriptPubKeyMan covers all types, please refer to + * https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.21.0.md#ismine-semantics + * for better understanding. + * + * For LegacyScriptPubKeyMan, + * ISMINE_NO: the scriptPubKey is not in the wallet; + * ISMINE_WATCH_ONLY: the scriptPubKey has been imported into the wallet; + * ISMINE_SPENDABLE: the scriptPubKey corresponds to an address owned by the wallet user (can spend with the private key); + * ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user; + * ISMINE_ALL: all ISMINE flags except for USED; + * ISMINE_ALL_USED: all ISMINE flags including USED; + * ISMINE_ENUM_ELEMENTS: the number of isminetype enum elements. + * + * For DescriptorScriptPubKeyMan and future ScriptPubKeyMan, + * ISMINE_NO: the scriptPubKey is not in the wallet; + * ISMINE_SPENDABLE: the scriptPubKey matches a scriptPubKey in the wallet. + * ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user. + * + */ enum isminetype : unsigned int { ISMINE_NO = 0, diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 1b057000d2..30832f983b 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -62,20 +62,25 @@ bool VerifyWallets(interfaces::Chain& chain) std::set<fs::path> wallet_paths; for (const auto& wallet_file : gArgs.GetArgs("-wallet")) { - const fs::path path = fs::absolute(wallet_file, GetWalletDir()); + const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), wallet_file); if (!wallet_paths.insert(path).second) { - chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file)); - return false; + chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file)); + continue; } DatabaseOptions options; DatabaseStatus status; + options.require_existing = true; options.verify = true; bilingual_str error_string; if (!MakeWalletDatabase(wallet_file, options, status, error_string)) { - chain.initError(error_string); - return false; + if (status == DatabaseStatus::FAILED_NOT_FOUND) { + chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s\n", error_string.original))); + } else { + chain.initError(error_string); + return false; + } } } @@ -85,13 +90,21 @@ bool VerifyWallets(interfaces::Chain& chain) bool LoadWallets(interfaces::Chain& chain) { try { + std::set<fs::path> wallet_paths; for (const std::string& name : gArgs.GetArgs("-wallet")) { + if (!wallet_paths.insert(name).second) { + continue; + } DatabaseOptions options; DatabaseStatus status; + options.require_existing = true; options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets() bilingual_str error; std::vector<bilingual_str> warnings; std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error); + if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) { + continue; + } std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(chain, name, std::move(database), options.create_flags, error, warnings) : nullptr; if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n"))); if (!pwallet) { diff --git a/src/wallet/load.h b/src/wallet/load.h index e12343de27..7910f0d6e1 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 9e36a09780..8505ddc309 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -340,8 +340,9 @@ RPCHelpMan importprunedfunds() CWallet* const pwallet = wallet.get(); CMutableTransaction tx; - if (!DecodeHexTx(tx, request.params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(tx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); + } uint256 hashTx = tx.GetHash(); CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION); @@ -932,6 +933,7 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d return "unspendable script"; case TxoutType::NONSTANDARD: case TxoutType::WITNESS_UNKNOWN: + case TxoutType::WITNESS_V1_TAPROOT: default: return "unrecognized script"; } @@ -1521,7 +1523,9 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue& // Need to ExpandPrivate to check if private keys are available for all pubkeys FlatSigningProvider expand_keys; std::vector<CScript> scripts; - parsed_desc->Expand(0, keys, scripts, expand_keys); + if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot expand descriptor. Probably because of hardened derivations without private keys provided"); + } parsed_desc->ExpandPrivate(0, keys, expand_keys); // Check if all private keys are provided @@ -1557,7 +1561,7 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue& } // Add descriptor to the wallet - auto spk_manager = pwallet->AddWalletDescriptor(w_desc, keys, label); + auto spk_manager = pwallet->AddWalletDescriptor(w_desc, keys, label, internal); if (spk_manager == nullptr) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor)); } @@ -1736,3 +1740,72 @@ RPCHelpMan importdescriptors() }, }; } + +RPCHelpMan listdescriptors() +{ + return RPCHelpMan{ + "listdescriptors", + "\nList descriptors imported into a descriptor-enabled wallet.", + {}, + RPCResult{ + RPCResult::Type::ARR, "", "Response is an array of descriptor objects", + { + {RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::STR, "desc", "Descriptor string representation"}, + {RPCResult::Type::NUM, "timestamp", "The creation time of the descriptor"}, + {RPCResult::Type::BOOL, "active", "Activeness flag"}, + {RPCResult::Type::BOOL, "internal", true, "Whether this is internal or external descriptor; defined only for active descriptors"}, + {RPCResult::Type::ARR_FIXED, "range", true, "Defined only for ranged descriptors", { + {RPCResult::Type::NUM, "", "Range start inclusive"}, + {RPCResult::Type::NUM, "", "Range end inclusive"}, + }}, + {RPCResult::Type::NUM, "next", true, "The next index to generate addresses from; defined only for ranged descriptors"}, + }}, + } + }, + RPCExamples{ + HelpExampleCli("listdescriptors", "") + HelpExampleRpc("listdescriptors", "") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); + if (!wallet) return NullUniValue; + + if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { + throw JSONRPCError(RPC_WALLET_ERROR, "listdescriptors is not available for non-descriptor wallets"); + } + + LOCK(wallet->cs_wallet); + + UniValue response(UniValue::VARR); + const auto active_spk_mans = wallet->GetActiveScriptPubKeyMans(); + for (const auto& spk_man : wallet->GetAllScriptPubKeyMans()) { + const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man); + if (!desc_spk_man) { + throw JSONRPCError(RPC_WALLET_ERROR, "Unexpected ScriptPubKey manager type."); + } + UniValue spk(UniValue::VOBJ); + LOCK(desc_spk_man->cs_desc_man); + const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor(); + spk.pushKV("desc", wallet_descriptor.descriptor->ToString()); + spk.pushKV("timestamp", wallet_descriptor.creation_time); + const bool active = active_spk_mans.count(desc_spk_man) != 0; + spk.pushKV("active", active); + const auto& type = wallet_descriptor.descriptor->GetOutputType(); + if (active && type != nullopt) { + spk.pushKV("internal", wallet->GetScriptPubKeyMan(*type, true) == desc_spk_man); + } + if (wallet_descriptor.descriptor->IsRange()) { + UniValue range(UniValue::VARR); + range.push_back(wallet_descriptor.range_start); + range.push_back(wallet_descriptor.range_end - 1); + spk.pushKV("range", range); + spk.pushKV("next", wallet_descriptor.next_index); + } + response.push_back(spk); + } + + return response; +}, + }; +} diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 70e99a308e..46de273d63 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -8,6 +8,7 @@ #include <interfaces/chain.h> #include <key_io.h> #include <node/context.h> +#include <optional.h> #include <outputtype.h> #include <policy/feerate.h> #include <policy/fees.h> @@ -47,8 +48,6 @@ using interfaces::FoundBlock; static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"}; -static const uint32_t WALLET_BTC_KB_TO_SAT_B = COIN / 1000; // 1 sat / B = 0.00001 BTC / kB - static inline bool GetAvoidReuseFlag(const CWallet* const pwallet, const UniValue& param) { bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool(); @@ -112,7 +111,7 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques if (wallets.empty()) { throw JSONRPCError( - RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)"); + RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)"); } throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED, "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path)."); @@ -198,36 +197,36 @@ static std::string LabelFromValue(const UniValue& value) /** * Update coin control with fee estimation based on the given parameters * - * @param[in] pwallet Wallet pointer - * @param[in,out] cc Coin control which is to be updated - * @param[in] estimate_mode String value (e.g. "ECONOMICAL") - * @param[in] estimate_param Parameter (blocks to confirm, explicit fee rate, etc) - * @throws a JSONRPCError if estimate_mode is unknown, or if estimate_param is missing when required + * @param[in] wallet Wallet reference + * @param[in,out] cc Coin control to be updated + * @param[in] conf_target UniValue integer; confirmation target in blocks, values between 1 and 1008 are valid per policy/fees.h; + * @param[in] estimate_mode UniValue string; fee estimation mode, valid values are "unset", "economical" or "conservative"; + * @param[in] fee_rate UniValue real; fee rate in sat/vB; + * if present, both conf_target and estimate_mode must either be null, or "unset" + * @param[in] override_min_fee bool; whether to set fOverrideFeeRate to true to disable minimum fee rate checks and instead + * verify only that fee_rate is greater than 0 + * @throws a JSONRPCError if conf_target, estimate_mode, or fee_rate contain invalid values or are in conflict */ -static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const UniValue& estimate_mode, const UniValue& estimate_param) +static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate, bool override_min_fee) { - if (!estimate_mode.isNull()) { - if (!FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter"); + if (!fee_rate.isNull()) { + if (!conf_target.isNull()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate."); } - } - - if (cc.m_fee_mode == FeeEstimateMode::BTC_KB || cc.m_fee_mode == FeeEstimateMode::SAT_B) { - if (estimate_param.isNull()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Selected estimate_mode requires a fee rate"); + if (!estimate_mode.isNull() && estimate_mode.get_str() != "unset") { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and fee_rate"); } - - CAmount fee_rate = AmountFromValue(estimate_param); - if (cc.m_fee_mode == FeeEstimateMode::SAT_B) { - fee_rate /= WALLET_BTC_KB_TO_SAT_B; - } - - cc.m_feerate = CFeeRate(fee_rate); - - // default RBF to true for explicit fee rate modes + cc.m_feerate = CFeeRate(AmountFromValue(fee_rate), COIN); + if (override_min_fee) cc.fOverrideFeeRate = true; + // Default RBF to true for explicit fee_rate, if unset. if (cc.m_signal_bip125_rbf == nullopt) cc.m_signal_bip125_rbf = true; - } else if (!estimate_param.isNull()) { - cc.m_confirm_target = ParseConfirmTarget(estimate_param, pwallet->chain().estimateMaxBlocks()); + return; + } + if (!estimate_mode.isNull() && !FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage()); + } + if (!conf_target.isNull()) { + cc.m_confirm_target = ParseConfirmTarget(conf_target, wallet.chain().estimateMaxBlocks()); } } @@ -310,7 +309,7 @@ static RPCHelpMan getrawchangeaddress() throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys"); } - OutputType output_type = pwallet->m_default_change_type.get_value_or(pwallet->m_default_address_type); + OutputType output_type = pwallet->m_default_change_type.value_or(pwallet->m_default_address_type); if (!request.params[0].isNull()) { if (!ParseOutputType(request.params[0].get_str(), output_type)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str())); @@ -397,7 +396,7 @@ void ParseRecipients(const UniValue& address_amounts, const UniValue& subtract_f } } -UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value) +UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value, bool verbose) { EnsureWalletIsUnlocked(pwallet); @@ -409,11 +408,18 @@ UniValue SendMoney(CWallet* const pwallet, const CCoinControl &coin_control, std int nChangePosRet = -1; bilingual_str error; CTransactionRef tx; - bool fCreated = pwallet->CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); + FeeCalculation fee_calc_out; + bool fCreated = pwallet->CreateTransaction(recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); if (!fCreated) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original); } pwallet->CommitTransaction(tx, std::move(map_value), {} /* orderForm */); + if (verbose) { + UniValue entry(UniValue::VOBJ); + entry.pushKV("txid", tx->GetHash().GetHex()); + entry.pushKV("fee_reason", StringForFeeReason(fee_calc_out.reason)); + return entry; + } return tx->GetHash().GetHex(); } @@ -426,29 +432,45 @@ static RPCHelpMan sendtoaddress() {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to send to."}, {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"}, {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n" - " This is not part of the transaction, just kept in your wallet."}, + "This is not part of the transaction, just kept in your wallet."}, {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n" - " to which you're sending the transaction. This is not part of the \n" - " transaction, just kept in your wallet."}, + "to which you're sending the transaction. This is not part of the \n" + "transaction, just kept in your wallet."}, {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n" - " The recipient will receive less bitcoins than you enter in the amount field."}, + "The recipient will receive less bitcoins than you enter in the amount field."}, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n" - " dirty if they have previously been used in a transaction."}, + "dirty if they have previously been used in a transaction."}, + {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If true, return extra information about the transaction."}, }, - RPCResult{ - RPCResult::Type::STR_HEX, "txid", "The transaction id." + { + RPCResult{"if verbose is not set or set to false", + RPCResult::Type::STR_HEX, "txid", "The transaction id." + }, + RPCResult{"if verbose is set to true", + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "txid", "The transaction id."}, + {RPCResult::Type::STR, "fee reason", "The transaction fee reason."} + }, + }, }, RPCExamples{ - HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1") - + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"seans outpost\"") - + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" true") - + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" false true 0.00002 " + (CURRENCY_UNIT + "/kB")) - + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" false true 2 " + (CURRENCY_ATOM + "/B")) - + HelpExampleRpc("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 0.1, \"donation\", \"seans outpost\"") + "\nSend 0.1 BTC\n" + + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1") + + "\nSend 0.1 BTC with a confirmation target of 6 blocks in economical fee estimate mode using positional arguments\n" + + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"sean's outpost\" false true 6 economical") + + "\nSend 0.1 BTC with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB, subtract fee from amount, BIP125-replaceable, using positional arguments\n" + + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"drinks\" \"room77\" true true null \"unset\" null 1.1") + + "\nSend 0.2 BTC with a confirmation target of 6 blocks in economical fee estimate mode using named arguments\n" + + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.2 conf_target=6 estimate_mode=\"economical\"") + + "\nSend 0.5 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n" + + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25") + + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25 subtractfeefromamount=false replaceable=true avoid_reuse=true comment=\"2 pizzas\" comment_to=\"jeremy\" verbose=true") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -483,7 +505,7 @@ static RPCHelpMan sendtoaddress() // We also enable partial spend avoidance if reuse avoidance is set. coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse; - SetFeeEstimateMode(pwallet, coin_control, request.params[7], request.params[6]); + SetFeeEstimateMode(*pwallet, coin_control, /* conf_target */ request.params[6], /* estimate_mode */ request.params[7], /* fee_rate */ request.params[9], /* override_min_fee */ false); EnsureWalletIsUnlocked(pwallet); @@ -497,8 +519,9 @@ static RPCHelpMan sendtoaddress() std::vector<CRecipient> recipients; ParseRecipients(address_amounts, subtractFeeFromAmount, recipients); + const bool verbose{request.params[10].isNull() ? false : request.params[10].get_bool()}; - return SendMoney(pwallet, coin_control, recipients, mapValue); + return SendMoney(pwallet, coin_control, recipients, mapValue, verbose); }, }; } @@ -604,7 +627,7 @@ static RPCHelpMan signmessage() throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } - const PKHash *pkhash = boost::get<PKHash>(&dest); + const PKHash* pkhash = std::get_if<PKHash>(&dest); if (!pkhash) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } @@ -842,22 +865,34 @@ static RPCHelpMan sendmany() {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"}, {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"}, {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The addresses.\n" - " The fee will be equally deducted from the amount of each selected address.\n" - " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" - " If no addresses are specified here, the sender pays the fee.", + "The fee will be equally deducted from the amount of each selected address.\n" + "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" + "If no addresses are specified here, the sender pays the fee.", { {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"}, }, }, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, + {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"verbose", RPCArg::Type::BOOL, /* default */ "false", "If true, return extra infomration about the transaction."}, + }, + { + RPCResult{"if verbose is not set or set to false", + RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n" + "the number of addresses." + }, + RPCResult{"if verbose is set to true", + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n" + "the number of addresses."}, + {RPCResult::Type::STR, "fee reason", "The transaction fee reason."} + }, + }, }, - RPCResult{ - RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n" - "the number of addresses." - }, RPCExamples{ "\nSend two amounts to two different addresses:\n" + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\"") + @@ -898,16 +933,18 @@ static RPCHelpMan sendmany() coin_control.m_signal_bip125_rbf = request.params[5].get_bool(); } - SetFeeEstimateMode(pwallet, coin_control, request.params[7], request.params[6]); + SetFeeEstimateMode(*pwallet, coin_control, /* conf_target */ request.params[6], /* estimate_mode */ request.params[7], /* fee_rate */ request.params[8], /* override_min_fee */ false); std::vector<CRecipient> recipients; ParseRecipients(sendTo, subtractFeeFromAmount, recipients); + const bool verbose{request.params[9].isNull() ? false : request.params[9].get_bool()}; - return SendMoney(pwallet, coin_control, recipients, std::move(mapValue)); + return SendMoney(pwallet, coin_control, recipients, std::move(mapValue), verbose); }, }; } + static RPCHelpMan addmultisigaddress() { return RPCHelpMan{"addmultisigaddress", @@ -1482,7 +1519,7 @@ static RPCHelpMan listsinceblock() {"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"}, {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"}, {"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n" - " (not guaranteed to work on pruned nodes)"}, + "(not guaranteed to work on pruned nodes)"}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -1536,8 +1573,7 @@ static RPCHelpMan listsinceblock() LOCK(wallet.cs_wallet); - // 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> height; // 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; @@ -2173,7 +2209,7 @@ static RPCHelpMan lockunspent() const uint256 txid(ParseHashO(o, "txid")); const int nOutput = find_value(o, "vout").get_int(); if (nOutput < 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); } const COutPoint outpt(txid, nOutput); @@ -2277,7 +2313,7 @@ static RPCHelpMan settxfee() "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n" "Can be deactivated by passing 0 as the fee. In that case automatic fee selection will be used by default.\n", { - {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kB"}, + {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kvB"}, }, RPCResult{ RPCResult::Type::BOOL, "", "Returns true if successful" @@ -2391,6 +2427,7 @@ static RPCHelpMan getwalletinfo() { {RPCResult::Type::STR, "walletname", "the wallet name"}, {RPCResult::Type::NUM, "walletversion", "the wallet version"}, + {RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"}, {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"}, {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"}, {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"}, @@ -2399,7 +2436,7 @@ static RPCHelpMan getwalletinfo() {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"}, {RPCResult::Type::NUM, "keypoolsize_hd_internal", "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"}, {RPCResult::Type::NUM_TIME, "unlocked_until", /* optional */ true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"}, - {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB"}, + {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kvB"}, {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "the Hash160 of the HD seed (only present when HD is enabled)"}, {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"}, {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"}, @@ -2434,6 +2471,7 @@ static RPCHelpMan getwalletinfo() int64_t kp_oldest = pwallet->GetOldestKeyPoolTime(); obj.pushKV("walletname", pwallet->GetName()); obj.pushKV("walletversion", pwallet->GetVersion()); + obj.pushKV("format", pwallet->GetDatabase().Format()); obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted)); obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending)); obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature)); @@ -2498,7 +2536,7 @@ static RPCHelpMan listwalletdir() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { UniValue wallets(UniValue::VARR); - for (const auto& path : ListWalletDir()) { + for (const auto& path : ListDatabases(GetWalletDir())) { UniValue wallet(UniValue::VOBJ); wallet.pushKV("name", path.string()); wallets.push_back(wallet); @@ -2577,7 +2615,18 @@ static RPCHelpMan loadwallet() if (!wallet) { // Map bad format to not found, since bad format is returned when the // wallet directory exists, but doesn't contain a data file. - RPCErrorCode code = status == DatabaseStatus::FAILED_NOT_FOUND || status == DatabaseStatus::FAILED_BAD_FORMAT ? RPC_WALLET_NOT_FOUND : RPC_WALLET_ERROR; + RPCErrorCode code = RPC_WALLET_ERROR; + switch (status) { + case DatabaseStatus::FAILED_NOT_FOUND: + case DatabaseStatus::FAILED_BAD_FORMAT: + code = RPC_WALLET_NOT_FOUND; + break; + case DatabaseStatus::FAILED_ALREADY_LOADED: + code = RPC_WALLET_ALREADY_LOADED; + break; + default: // RPC_WALLET_ERROR is returned for all other cases. + break; + } throw JSONRPCError(code, error.original); } @@ -2709,10 +2758,19 @@ static RPCHelpMan createwallet() flags |= WALLET_FLAG_AVOID_REUSE; } if (!request.params[5].isNull() && request.params[5].get_bool()) { +#ifndef USE_SQLITE + throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)"); +#endif flags |= WALLET_FLAG_DESCRIPTORS; warnings.emplace_back(Untranslated("Wallet is an experimental descriptor wallet")); } +#ifndef USE_BDB + if (!(flags & WALLET_FLAG_DESCRIPTORS)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without bdb support (required for legacy wallets)"); + } +#endif + DatabaseOptions options; DatabaseStatus status; options.require_create = true; @@ -2741,7 +2799,7 @@ static RPCHelpMan unloadwallet() "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n" "Specifying the wallet name on a wallet endpoint is invalid.", { - {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC request", "The name of the wallet to unload."}, + {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC endpoint", "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."}, {"load_on_startup", RPCArg::Type::BOOL, /* default */ "null", "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."}, }, RPCResult{RPCResult::Type::OBJ, "", "", { @@ -2755,8 +2813,8 @@ static RPCHelpMan unloadwallet() { std::string wallet_name; if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) { - if (!request.params[0].isNull()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot unload the requested wallet"); + if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets"); } } else { wallet_name = request.params[0].get_str(); @@ -2801,7 +2859,7 @@ static RPCHelpMan listunspent() }, }, {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true", "Include outputs that are not safe to spend\n" - " See description of \"safe\" attribute below."}, + "See description of \"safe\" attribute below."}, {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options", { {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""}, @@ -2955,7 +3013,7 @@ static RPCHelpMan listunspent() std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey); if (provider) { if (scriptPubKey.IsPayToScriptHash()) { - const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address)); + const CScriptID& hash = CScriptID(std::get<ScriptHash>(address)); CScript redeemScript; if (provider->GetCScript(hash, redeemScript)) { entry.pushKV("redeemScript", HexStr(redeemScript)); @@ -2965,7 +3023,7 @@ static RPCHelpMan listunspent() bool extracted = ExtractDestination(redeemScript, witness_destination); CHECK_NONFATAL(extracted); // Also return the witness script - const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(witness_destination); + const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(witness_destination); CScriptID id; CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin()); CScript witnessScript; @@ -2975,7 +3033,7 @@ static RPCHelpMan listunspent() } } } else if (scriptPubKey.IsPayToWitnessScriptHash()) { - const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(address); + const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(address); CScriptID id; CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin()); CScript witnessScript; @@ -3008,7 +3066,7 @@ static RPCHelpMan listunspent() }; } -void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options, CCoinControl& coinControl) +void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, const UniValue& options, CCoinControl& coinControl, bool override_min_fee) { // 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 @@ -3041,7 +3099,8 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f {"lockUnspents", UniValueType(UniValue::VBOOL)}, {"lock_unspents", UniValueType(UniValue::VBOOL)}, {"locktime", UniValueType(UniValue::VNUM)}, - {"feeRate", UniValueType()}, // will be checked below + {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode() + {"feeRate", UniValueType()}, // will be checked by AmountFromValue() below {"psbt", UniValueType(UniValue::VBOOL)}, {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)}, {"subtract_fee_from_outputs", UniValueType(UniValue::VARR)}, @@ -3088,10 +3147,12 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool(); } - if (options.exists("feeRate")) - { + if (options.exists("feeRate")) { + if (options.exists("fee_rate")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both fee_rate (" + CURRENCY_ATOM + "/vB) and feeRate (" + CURRENCY_UNIT + "/kvB)"); + } if (options.exists("conf_target")) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate."); } if (options.exists("estimate_mode")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate"); @@ -3106,7 +3167,7 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f if (options.exists("replaceable")) { coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool(); } - SetFeeEstimateMode(pwallet, coinControl, options["estimate_mode"], options["conf_target"]); + SetFeeEstimateMode(*pwallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee); } } else { // if options is null and not a bool @@ -3163,18 +3224,19 @@ static RPCHelpMan fundrawtransaction() "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n" "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."}, {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, - {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"}, + {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."}, {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The integers.\n" - " The fee will be equally deducted from the amount of each specified output.\n" - " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" - " If no outputs are specified here, the sender pays the fee.", + "The fee will be equally deducted from the amount of each specified output.\n" + "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" + "If no outputs are specified here, the sender pays the fee.", { {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" - " Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + "Allows this transaction to be replaced by a transaction with higher fees"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, }, @@ -3226,7 +3288,7 @@ static RPCHelpMan fundrawtransaction() CCoinControl coin_control; // Automatically select (additional) coins. Can be overridden by options.add_inputs. coin_control.m_add_inputs = true; - FundTransaction(pwallet, tx, fee, change_position, request.params[1], coin_control); + FundTransaction(pwallet, tx, fee, change_position, request.params[1], coin_control, /* override_min_fee */ true); UniValue result(UniValue::VOBJ); result.pushKV("hex", EncodeHexTx(CTransaction(tx))); @@ -3300,8 +3362,8 @@ RPCHelpMan signrawtransactionwithwallet() RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true); CMutableTransaction mtx; - if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) { - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + if (!DecodeHexTx(mtx, request.params[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); } // Sign the transaction @@ -3334,34 +3396,38 @@ RPCHelpMan signrawtransactionwithwallet() static RPCHelpMan bumpfee_helper(std::string method_name) { bool want_psbt = method_name == "psbtbumpfee"; + const std::string incremental_fee{CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE).ToString(FeeEstimateMode::SAT_VB)}; return RPCHelpMan{method_name, "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n" + std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") + "An opt-in RBF transaction with the given txid must be in the wallet.\n" - "The command will pay the additional fee by reducing change outputs or adding inputs when necessary. It may add a new change output if one does not already exist.\n" + "The command will pay the additional fee by reducing change outputs or adding inputs when necessary.\n" + "It may add a new change output if one does not already exist.\n" "All inputs in the original transaction will be included in the replacement transaction.\n" "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n" - "By default, the new fee will be calculated automatically using estimatesmartfee.\n" + "By default, the new fee will be calculated automatically using the estimatesmartfee RPC.\n" "The user can specify a confirmation target for estimatesmartfee.\n" - "Alternatively, the user can specify a fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction.\n" + "Alternatively, the user can specify a fee rate in " + CURRENCY_ATOM + "/vB for the new transaction.\n" "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" - "returned by getnetworkinfo) to enter the node's mempool.\n", + "returned by getnetworkinfo) to enter the node's mempool.\n" + "* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"}, - {"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'conf_target'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n" - " Specify a fee rate instead of relying on the built-in fee estimator.\n" - "Must be at least 0.0001 " + CURRENCY_UNIT + " per kB higher than the current transaction fee rate.\n"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks\n"}, + {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", + "\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n" + "Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n" + "WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"}, {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n" - " marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n" - " be left unchanged from the original. If false, any input sequence numbers in the\n" - " original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n" - " so the new transaction will not be explicitly bip-125 replaceable (though it may\n" - " still be replaceable in practice, for example if it has unconfirmed ancestors which\n" - " are replaceable)."}, + "marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n" + "be left unchanged from the original. If false, any input sequence numbers in the\n" + "original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n" + "so the new transaction will not be explicitly bip-125 replaceable (though it may\n" + "still be replaceable in practice, for example if it has unconfirmed ancestors which\n" + "are replaceable).\n"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, }, @@ -3394,10 +3460,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) CWallet* const pwallet = wallet.get(); if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) { - if (!pwallet->chain().rpcEnableDeprecated("bumpfee")) { - throw JSONRPCError(RPC_METHOD_DEPRECATED, "Using bumpfee with wallets that have private keys disabled is deprecated. Use psbtbumpfee instead or restart bitcoind with -deprecatedrpc=bumpfee. This functionality will be removed in 0.22"); - } - want_psbt = true; + throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead."); } RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ}); @@ -3414,7 +3477,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name) { {"confTarget", UniValueType(UniValue::VNUM)}, {"conf_target", UniValueType(UniValue::VNUM)}, - {"fee_rate", UniValueType(UniValue::VNUM)}, + {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode() {"replaceable", UniValueType(UniValue::VBOOL)}, {"estimate_mode", UniValueType(UniValue::VSTR)}, }, @@ -3426,23 +3489,10 @@ static RPCHelpMan bumpfee_helper(std::string method_name) auto conf_target = options.exists("confTarget") ? options["confTarget"] : options["conf_target"]; - if (!conf_target.isNull()) { - if (options.exists("fee_rate")) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "conf_target can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate."); - } - coin_control.m_confirm_target = ParseConfirmTarget(conf_target, pwallet->chain().estimateMaxBlocks()); - } else if (options.exists("fee_rate")) { - CFeeRate fee_rate(AmountFromValue(options["fee_rate"])); - if (fee_rate <= CFeeRate(0)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid fee_rate %s (must be greater than 0)", fee_rate.ToString())); - } - coin_control.m_feerate = fee_rate; - } - if (options.exists("replaceable")) { coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool(); } - SetFeeEstimateMode(pwallet, coin_control, options["estimate_mode"], conf_target); + SetFeeEstimateMode(*pwallet, coin_control, conf_target, options["estimate_mode"], options["fee_rate"], /* override_min_fee */ false); } // Make sure the results are valid at least up to the most recent block @@ -3603,7 +3653,7 @@ static RPCHelpMan rescanblockchain() }; } -class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue> +class DescribeWalletAddressVisitor { public: const SigningProvider * const provider; @@ -3622,7 +3672,7 @@ public: UniValue subobj(UniValue::VOBJ); UniValue detail = DescribeAddress(embedded); subobj.pushKVs(detail); - UniValue wallet_detail = boost::apply_visitor(*this, embedded); + UniValue wallet_detail = std::visit(*this, embedded); subobj.pushKVs(wallet_detail); subobj.pushKV("address", EncodeDestination(embedded)); subobj.pushKV("scriptPubKey", HexStr(subscript)); @@ -3705,7 +3755,7 @@ static UniValue DescribeWalletAddress(const CWallet* const pwallet, const CTxDes provider = pwallet->GetSolvingProvider(script); } ret.pushKVs(detail); - ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(provider.get()), dest)); + ret.pushKVs(std::visit(DescribeWalletAddressVisitor(provider.get()), dest)); return ret; } @@ -3743,7 +3793,7 @@ RPCHelpMan getaddressinfo() {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program."}, {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program."}, {RPCResult::Type::STR, "script", /* optional */ true, "The output script type. Only if isscript is true and the redeemscript is known. Possible\n" - " types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash,\n" + "types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash,\n" "witness_v0_scripthash, witness_unknown."}, {RPCResult::Type::STR_HEX, "hex", /* optional */ true, "The redeemscript for the p2sh address."}, {RPCResult::Type::ARR, "pubkeys", /* optional */ true, "Array of pubkeys associated with the known redeemscript (only if script is multisig).", @@ -3781,13 +3831,19 @@ RPCHelpMan getaddressinfo() LOCK(pwallet->cs_wallet); - UniValue ret(UniValue::VOBJ); - CTxDestination dest = DecodeDestination(request.params[0].get_str()); + std::string error_msg; + CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg); + // Make sure the destination is valid if (!IsValidDestination(dest)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + // Set generic error message in case 'DecodeDestination' didn't set it + if (error_msg.empty()) error_msg = "Invalid address"; + + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error_msg); } + UniValue ret(UniValue::VOBJ); + std::string currentAddress = EncodeDestination(dest); ret.pushKV("address", currentAddress); @@ -3962,7 +4018,7 @@ static RPCHelpMan send() "\nEXPERIMENTAL warning: this call may be changed in future releases.\n" "\nSend a transaction.\n", { - {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "A JSON array with outputs (key-value pairs), where none of the keys are duplicated.\n" + {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n" "That is, each address can only appear once and there can only be one 'data' object.\n" "For convenience, a dictionary, which holds the key-value pairs directly, is also accepted.", { @@ -3978,9 +4034,10 @@ static RPCHelpMan send() }, }, }, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, + {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { {"add_inputs", RPCArg::Type::BOOL, /* default */ "false", "If inputs are specified, automatically include more if they are not enough."}, @@ -3988,9 +4045,10 @@ static RPCHelpMan send() {"change_address", RPCArg::Type::STR_HEX, /* default */ "pool address", "The bitcoin address to receive the change"}, {"change_position", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"}, {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, - {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, + {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, {"include_watching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n" "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n" "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."}, @@ -4004,7 +4062,7 @@ static RPCHelpMan send() {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"}, {"lock_unspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, {"psbt", RPCArg::Type::BOOL, /* default */ "automatic", "Always return a PSBT, implies add_to_wallet=false."}, - {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "A JSON array of integers.\n" + {"subtract_fee_from_outputs", RPCArg::Type::ARR, /* default */ "empty array", "Outputs to subtract the fee from, specified as integer indices.\n" "The fee will be equally deducted from the amount of each specified output.\n" "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" "If no outputs are specified here, the sender pays the fee.", @@ -4013,7 +4071,7 @@ static RPCHelpMan send() }, }, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" - " Allows this transaction to be replaced by a transaction with higher fees"}, + "Allows this transaction to be replaced by a transaction with higher fees"}, }, "options"}, }, @@ -4027,18 +4085,25 @@ static RPCHelpMan send() } }, RPCExamples{"" - "\nSend with a fee rate of 1 satoshi per byte\n" - + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 sat/b\n") + - "\nCreate a transaction that should confirm the next block, with a specific input, and return result without adding to wallet or broadcasting to the network\n" + "\nSend 0.1 BTC with a confirmation target of 6 blocks in economical fee estimate mode\n" + + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 6 economical\n") + + "Send 0.2 BTC with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB using positional arguments\n" + + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.2}' null \"unset\" 1.1\n") + + "Send 0.2 BTC with a fee rate of 1 " + CURRENCY_ATOM + "/vB using the options argument\n" + + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.2}' null \"unset\" null '{\"fee_rate\": 1}'\n") + + "Send 0.3 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n" + + HelpExampleCli("-named send", "outputs='{\"" + EXAMPLE_ADDRESS[0] + "\": 0.3}' fee_rate=25\n") + + "Create a transaction that should confirm the next block, with a specific input, and return result without adding to wallet or broadcasting to the network\n" + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 economical '{\"add_to_wallet\": false, \"inputs\": [{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\", \"vout\":1}]}'") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { RPCTypeCheck(request.params, { - UniValueType(), // ARR or OBJ, checked later - UniValue::VNUM, - UniValue::VSTR, - UniValue::VOBJ + UniValueType(), // outputs (ARR or OBJ, checked later) + UniValue::VNUM, // conf_target + UniValue::VSTR, // estimate_mode + UniValueType(), // fee_rate, will be checked by AmountFromValue() in SetFeeEstimateMode() + UniValue::VOBJ, // options }, true ); @@ -4046,18 +4111,28 @@ static RPCHelpMan send() if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); - UniValue options = request.params[3]; - if (options.exists("feeRate") || options.exists("fee_rate") || options.exists("estimate_mode") || options.exists("conf_target")) { + UniValue options{request.params[4].isNull() ? UniValue::VOBJ : request.params[4]}; + if (options.exists("conf_target") || options.exists("estimate_mode")) { if (!request.params[1].isNull() || !request.params[2].isNull()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Use either conf_target and estimate_mode or the options dictionary to control fee rate"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Pass conf_target and estimate_mode either as arguments or in the options object, but not both"); } } else { options.pushKV("conf_target", request.params[1]); options.pushKV("estimate_mode", request.params[2]); } + if (options.exists("fee_rate")) { + if (!request.params[3].isNull()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Pass the fee_rate either as an argument, or in the options object, but not both"); + } + } else { + options.pushKV("fee_rate", request.params[3]); + } if (!options["conf_target"].isNull() && (options["estimate_mode"].isNull() || (options["estimate_mode"].get_str() == "unset"))) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Specify estimate_mode"); } + if (options.exists("feeRate")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Use fee_rate (" + CURRENCY_ATOM + "/vB) instead of feeRate"); + } if (options.exists("changeAddress")) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_address"); } @@ -4085,9 +4160,9 @@ static RPCHelpMan send() CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf); CCoinControl coin_control; // Automatically select coins, unless at least one is manually selected. Can - // be overriden by options.add_inputs. + // be overridden by options.add_inputs. coin_control.m_add_inputs = rawTx.vin.size() == 0; - FundTransaction(pwallet, rawTx, fee, change_position, options, coin_control); + FundTransaction(pwallet, rawTx, fee, change_position, options, coin_control, /* override_min_fee */ false); bool add_to_wallet = true; if (options.exists("add_to_wallet")) { @@ -4143,11 +4218,11 @@ static RPCHelpMan sethdseed() HELP_REQUIRING_PASSPHRASE, { {"newkeypool", RPCArg::Type::BOOL, /* default */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n" - " If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n" - " If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n" - " keypool will be used until it has been depleted."}, + "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n" + "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n" + "keypool will be used until it has been depleted."}, {"seed", RPCArg::Type::STR, /* default */ "random seed", "The WIF private key to use as the new HD seed.\n" - " The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"}, + "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"}, }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{ @@ -4172,7 +4247,7 @@ static RPCHelpMan sethdseed() // Do not do anything to non-HD wallets if (!pwallet->CanSupportFeature(FEATURE_HD)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD"); + throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set an HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD"); } EnsureWalletIsUnlocked(pwallet); @@ -4292,7 +4367,7 @@ static RPCHelpMan walletcreatefundedpsbt() {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n" "That is, each address can only appear once and there can only be one 'data' object.\n" "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" - " accepted as second parameter.", + "accepted as second parameter.", { {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", { @@ -4315,18 +4390,19 @@ static RPCHelpMan walletcreatefundedpsbt() {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."}, {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only"}, {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"}, - {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"}, + {"fee_rate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_ATOM + "/vB."}, + {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set, fall back to wallet fee estimation", "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."}, {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The outputs to subtract the fee from.\n" - " The fee will be equally deducted from the amount of each specified output.\n" - " Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" - " If no outputs are specified here, the sender pays the fee.", + "The fee will be equally deducted from the amount of each specified output.\n" + "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n" + "If no outputs are specified here, the sender pays the fee.", { {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n" - " Allows this transaction to be replaced by a transaction with higher fees"}, - {"conf_target", RPCArg::Type::NUM, /* default */ "fall back to wallet's confirmation target (txconfirmtarget)", "Confirmation target (in blocks)"}, + "Allows this transaction to be replaced by a transaction with higher fees"}, + {"conf_target", RPCArg::Type::NUM, /* default */ "wallet -txconfirmtarget", "Confirmation target in blocks"}, {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n" " \"" + FeeModes("\"\n\"") + "\""}, }, @@ -4373,7 +4449,7 @@ static RPCHelpMan walletcreatefundedpsbt() // Automatically select coins, unless at least one is manually selected. Can // be overridden by options.add_inputs. coin_control.m_add_inputs = rawTx.vin.size() == 0; - FundTransaction(pwallet, rawTx, fee, change_position, request.params[3], coin_control); + FundTransaction(pwallet, rawTx, fee, change_position, request.params[3], coin_control, /* override_min_fee */ true); // Make a blank psbt PartiallySignedTransaction psbtx(rawTx); @@ -4402,12 +4478,21 @@ static RPCHelpMan walletcreatefundedpsbt() static RPCHelpMan upgradewallet() { return RPCHelpMan{"upgradewallet", - "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified\n" + "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n" "New keys may be generated and a new wallet backup will need to be made.", { - {"version", RPCArg::Type::NUM, /* default */ strprintf("%d", FEATURE_LATEST), "The version number to upgrade to. Default is the latest wallet version"} + {"version", RPCArg::Type::NUM, /* default */ strprintf("%d", FEATURE_LATEST), "The version number to upgrade to. Default is the latest wallet version."} + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"}, + {RPCResult::Type::NUM, "previous_version", "Version of wallet before this operation"}, + {RPCResult::Type::NUM, "current_version", "Version of wallet after this operation"}, + {RPCResult::Type::STR, "result", /* optional */ true, "Description of result, if no error"}, + {RPCResult::Type::STR, "error", /* optional */ true, "Error message (if there is one)"} + }, }, - RPCResults{}, RPCExamples{ HelpExampleCli("upgradewallet", "169900") + HelpExampleRpc("upgradewallet", "169900") @@ -4426,13 +4511,31 @@ static RPCHelpMan upgradewallet() if (!request.params[0].isNull()) { version = request.params[0].get_int(); } - bilingual_str error; - std::vector<bilingual_str> warnings; - if (!pwallet->UpgradeWallet(version, error, warnings)) { - throw JSONRPCError(RPC_WALLET_ERROR, error.original); + const int previous_version{pwallet->GetVersion()}; + const bool wallet_upgraded{pwallet->UpgradeWallet(version, error)}; + const int current_version{pwallet->GetVersion()}; + std::string result; + + if (wallet_upgraded) { + if (previous_version == current_version) { + result = "Already at latest version. Wallet version unchanged."; + } else { + result = strprintf("Wallet upgraded successfully from version %i to version %i.", previous_version, current_version); + } + } + + UniValue obj(UniValue::VOBJ); + obj.pushKV("wallet_name", pwallet->GetName()); + obj.pushKV("previous_version", previous_version); + obj.pushKV("current_version", current_version); + if (!result.empty()) { + obj.pushKV("result", result); + } else { + CHECK_NONFATAL(!error.empty()); + obj.pushKV("error", error.original); } - return error.original; + return obj; }, }; } @@ -4448,73 +4551,75 @@ RPCHelpMan importprunedfunds(); RPCHelpMan removeprunedfunds(); RPCHelpMan importmulti(); RPCHelpMan importdescriptors(); +RPCHelpMan listdescriptors(); Span<const CRPCCommand> GetWalletRPCCommands() { // clang-format off static const CRPCCommand commands[] = -{ // category name actor (function) argNames - // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} }, - { "wallet", "abandontransaction", &abandontransaction, {"txid"} }, - { "wallet", "abortrescan", &abortrescan, {} }, - { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} }, - { "wallet", "backupwallet", &backupwallet, {"destination"} }, - { "wallet", "bumpfee", &bumpfee, {"txid", "options"} }, - { "wallet", "psbtbumpfee", &psbtbumpfee, {"txid", "options"} }, - { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors", "load_on_startup"} }, - { "wallet", "dumpprivkey", &dumpprivkey, {"address"} }, - { "wallet", "dumpwallet", &dumpwallet, {"filename"} }, - { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, - { "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} }, - { "wallet", "getaddressinfo", &getaddressinfo, {"address"} }, - { "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly","avoid_reuse"} }, - { "wallet", "getnewaddress", &getnewaddress, {"label","address_type"} }, - { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} }, - { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} }, - { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} }, - { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly","verbose"} }, - { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} }, - { "wallet", "getbalances", &getbalances, {} }, - { "wallet", "getwalletinfo", &getwalletinfo, {} }, - { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} }, - { "wallet", "importdescriptors", &importdescriptors, {"requests"} }, - { "wallet", "importmulti", &importmulti, {"requests","options"} }, - { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} }, - { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} }, - { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} }, - { "wallet", "importwallet", &importwallet, {"filename"} }, - { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} }, - { "wallet", "listaddressgroupings", &listaddressgroupings, {} }, - { "wallet", "listlabels", &listlabels, {"purpose"} }, - { "wallet", "listlockunspent", &listlockunspent, {} }, - { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} }, - { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} }, - { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} }, - { "wallet", "listtransactions", &listtransactions, {"label|dummy","count","skip","include_watchonly"} }, - { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} }, - { "wallet", "listwalletdir", &listwalletdir, {} }, - { "wallet", "listwallets", &listwallets, {} }, - { "wallet", "loadwallet", &loadwallet, {"filename", "load_on_startup"} }, - { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} }, - { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, - { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} }, - { "wallet", "send", &send, {"outputs","conf_target","estimate_mode","options"} }, - { "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, - { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse"} }, - { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} }, - { "wallet", "setlabel", &setlabel, {"address","label"} }, - { "wallet", "settxfee", &settxfee, {"amount"} }, - { "wallet", "setwalletflag", &setwalletflag, {"flag","value"} }, - { "wallet", "signmessage", &signmessage, {"address","message"} }, - { "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} }, - { "wallet", "unloadwallet", &unloadwallet, {"wallet_name", "load_on_startup"} }, - { "wallet", "upgradewallet", &upgradewallet, {"version"} }, - { "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} }, - { "wallet", "walletlock", &walletlock, {} }, - { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} }, - { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, - { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} }, +{ // category actor (function) + // ------------------ ------------------------ + { "rawtransactions", &fundrawtransaction, }, + { "wallet", &abandontransaction, }, + { "wallet", &abortrescan, }, + { "wallet", &addmultisigaddress, }, + { "wallet", &backupwallet, }, + { "wallet", &bumpfee, }, + { "wallet", &psbtbumpfee, }, + { "wallet", &createwallet, }, + { "wallet", &dumpprivkey, }, + { "wallet", &dumpwallet, }, + { "wallet", &encryptwallet, }, + { "wallet", &getaddressesbylabel, }, + { "wallet", &getaddressinfo, }, + { "wallet", &getbalance, }, + { "wallet", &getnewaddress, }, + { "wallet", &getrawchangeaddress, }, + { "wallet", &getreceivedbyaddress, }, + { "wallet", &getreceivedbylabel, }, + { "wallet", &gettransaction, }, + { "wallet", &getunconfirmedbalance, }, + { "wallet", &getbalances, }, + { "wallet", &getwalletinfo, }, + { "wallet", &importaddress, }, + { "wallet", &importdescriptors, }, + { "wallet", &importmulti, }, + { "wallet", &importprivkey, }, + { "wallet", &importprunedfunds, }, + { "wallet", &importpubkey, }, + { "wallet", &importwallet, }, + { "wallet", &keypoolrefill, }, + { "wallet", &listaddressgroupings, }, + { "wallet", &listdescriptors, }, + { "wallet", &listlabels, }, + { "wallet", &listlockunspent, }, + { "wallet", &listreceivedbyaddress, }, + { "wallet", &listreceivedbylabel, }, + { "wallet", &listsinceblock, }, + { "wallet", &listtransactions, }, + { "wallet", &listunspent, }, + { "wallet", &listwalletdir, }, + { "wallet", &listwallets, }, + { "wallet", &loadwallet, }, + { "wallet", &lockunspent, }, + { "wallet", &removeprunedfunds, }, + { "wallet", &rescanblockchain, }, + { "wallet", &send, }, + { "wallet", &sendmany, }, + { "wallet", &sendtoaddress, }, + { "wallet", &sethdseed, }, + { "wallet", &setlabel, }, + { "wallet", &settxfee, }, + { "wallet", &setwalletflag, }, + { "wallet", &signmessage, }, + { "wallet", &signrawtransactionwithwallet, }, + { "wallet", &unloadwallet, }, + { "wallet", &upgradewallet, }, + { "wallet", &walletcreatefundedpsbt, }, + { "wallet", &walletlock, }, + { "wallet", &walletpassphrase, }, + { "wallet", &walletpassphrasechange, }, + { "wallet", &walletprocesspsbt, }, }; // clang-format on return MakeSpan(commands); diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp index 225b975067..09a9ec68cd 100644 --- a/src/wallet/salvage.cpp +++ b/src/wallet/salvage.cpp @@ -6,6 +6,7 @@ #include <fs.h> #include <streams.h> #include <util/translation.h> +#include <wallet/bdb.h> #include <wallet/salvage.h> #include <wallet/wallet.h> #include <wallet/walletdb.h> @@ -27,11 +28,13 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v DatabaseStatus status; options.require_existing = true; options.verify = false; + options.require_format = DatabaseFormat::BERKELEY; std::unique_ptr<WalletDatabase> database = MakeDatabase(file_path, options, status, error); if (!database) return false; - std::string filename; - std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, filename); + BerkeleyDatabase& berkeley_database = static_cast<BerkeleyDatabase&>(*database); + std::string filename = berkeley_database.Filename(); + std::shared_ptr<BerkeleyEnvironment> env = berkeley_database.env; if (!env->Open(error)) { return false; diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 435716e56a..15972fe7bb 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -3,12 +3,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <key_io.h> +#include <logging.h> #include <outputtype.h> #include <script/descriptor.h> #include <script/sign.h> #include <util/bip32.h> #include <util/strencodings.h> #include <util/string.h> +#include <util/system.h> +#include <util/time.h> #include <util/translation.h> #include <wallet/scriptpubkeyman.h> @@ -96,6 +99,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s case TxoutType::NONSTANDARD: case TxoutType::NULL_DATA: case TxoutType::WITNESS_UNKNOWN: + case TxoutType::WITNESS_V1_TAPROOT: break; case TxoutType::PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); @@ -437,12 +441,12 @@ bool LegacyScriptPubKeyMan::CanGetAddresses(bool internal) const return keypool_has_keys; } -bool LegacyScriptPubKeyMan::Upgrade(int prev_version, bilingual_str& error) +bool LegacyScriptPubKeyMan::Upgrade(int prev_version, int new_version, bilingual_str& error) { LOCK(cs_KeyStore); bool hd_upgrade = false; bool split_upgrade = false; - if (m_storage.CanSupportFeature(FEATURE_HD) && !IsHDEnabled()) { + if (IsFeatureSupported(new_version, FEATURE_HD) && !IsHDEnabled()) { WalletLogPrintf("Upgrading wallet to HD\n"); m_storage.SetMinVersion(FEATURE_HD); @@ -452,10 +456,17 @@ bool LegacyScriptPubKeyMan::Upgrade(int prev_version, bilingual_str& error) hd_upgrade = true; } // Upgrade to HD chain split if necessary - if (m_storage.CanSupportFeature(FEATURE_HD_SPLIT) && CHDChain::VERSION_HD_CHAIN_SPLIT) { + if (!IsFeatureSupported(prev_version, FEATURE_HD_SPLIT) && IsFeatureSupported(new_version, FEATURE_HD_SPLIT)) { WalletLogPrintf("Upgrading wallet to use HD chain split\n"); m_storage.SetMinVersion(FEATURE_PRE_SPLIT_KEYPOOL); split_upgrade = FEATURE_HD_SPLIT > prev_version; + // Upgrade the HDChain + if (m_hd_chain.nVersion < CHDChain::VERSION_HD_CHAIN_SPLIT) { + m_hd_chain.nVersion = CHDChain::VERSION_HD_CHAIN_SPLIT; + if (!WalletBatch(m_storage.GetDatabase()).WriteHDChain(m_hd_chain)) { + throw std::runtime_error(std::string(__func__) + ": writing chain failed"); + } + } } // Mark all keys currently in the keypool as pre-split if (split_upgrade) { diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 14fb1fa89f..8f6b69bc78 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -11,6 +11,7 @@ #include <script/standard.h> #include <util/error.h> #include <util/message.h> +#include <util/time.h> #include <wallet/crypter.h> #include <wallet/ismine.h> #include <wallet/walletdb.h> @@ -33,11 +34,11 @@ class WalletStorage public: virtual ~WalletStorage() = default; virtual const std::string GetDisplayName() const = 0; - virtual WalletDatabase& GetDatabase() = 0; + virtual WalletDatabase& GetDatabase() const = 0; virtual bool IsWalletFlagSet(uint64_t) const = 0; virtual void UnsetBlankWalletFlag(WalletBatch&) = 0; virtual bool CanSupportFeature(enum WalletFeature) const = 0; - virtual void SetMinVersion(enum WalletFeature, WalletBatch* = nullptr, bool = false) = 0; + virtual void SetMinVersion(enum WalletFeature, WalletBatch* = nullptr) = 0; virtual const CKeyingMaterial& GetEncryptionKey() const = 0; virtual bool HasEncryptionKeys() const = 0; virtual bool IsLocked() const = 0; @@ -171,7 +172,7 @@ protected: WalletStorage& m_storage; public: - ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {} + explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {} virtual ~ScriptPubKeyMan() {}; virtual bool GetNewDestination(const OutputType type, CTxDestination& dest, std::string& error) { return false; } virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; } @@ -206,7 +207,7 @@ public: virtual bool CanGetAddresses(bool internal = false) const { return false; } /** Upgrades the wallet to the specified version */ - virtual bool Upgrade(int prev_version, bilingual_str& error) { return false; } + virtual bool Upgrade(int prev_version, int new_version, bilingual_str& error) { return false; } virtual bool HavePrivateKeys() const { return false; } @@ -303,7 +304,7 @@ private: /* the HD chain data model (external chain counters) */ CHDChain m_hd_chain; - std::unordered_map<CKeyID, CHDChain, KeyIDHasher> m_inactive_hd_chains; + std::unordered_map<CKeyID, CHDChain, SaltedSipHasher> m_inactive_hd_chains; /* HD derive new child key (on internal or external chain) */ void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); @@ -371,7 +372,7 @@ public: bool SetupGeneration(bool force = false) override; - bool Upgrade(int prev_version, bilingual_str& error) override; + bool Upgrade(int prev_version, int new_version, bilingual_str& error) override; bool HavePrivateKeys() const override; @@ -503,7 +504,7 @@ class LegacySigningProvider : public SigningProvider private: const LegacyScriptPubKeyMan& m_spk_man; public: - LegacySigningProvider(const LegacyScriptPubKeyMan& spk_man) : m_spk_man(spk_man) {} + explicit LegacySigningProvider(const LegacyScriptPubKeyMan& spk_man) : m_spk_man(spk_man) {} bool GetCScript(const CScriptID &scriptid, CScript& script) const override { return m_spk_man.GetCScript(scriptid, script); } bool HaveCScript(const CScriptID &scriptid) const override { return m_spk_man.HaveCScript(scriptid); } diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp new file mode 100644 index 0000000000..0fb3b1d3c4 --- /dev/null +++ b/src/wallet/sqlite.cpp @@ -0,0 +1,591 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <wallet/sqlite.h> + +#include <chainparams.h> +#include <crypto/common.h> +#include <logging.h> +#include <sync.h> +#include <util/memory.h> +#include <util/strencodings.h> +#include <util/system.h> +#include <util/translation.h> +#include <wallet/db.h> + +#include <sqlite3.h> +#include <stdint.h> + +static constexpr int32_t WALLET_SCHEMA_VERSION = 0; + +static Mutex g_sqlite_mutex; +static int g_sqlite_count GUARDED_BY(g_sqlite_mutex) = 0; + +static void ErrorLogCallback(void* arg, int code, const char* msg) +{ + // From sqlite3_config() documentation for the SQLITE_CONFIG_LOG option: + // "The void pointer that is the second argument to SQLITE_CONFIG_LOG is passed through as + // the first parameter to the application-defined logger function whenever that function is + // invoked." + // Assert that this is the case: + assert(arg == nullptr); + LogPrintf("SQLite Error. Code: %d. Message: %s\n", code, msg); +} + +SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, bool mock) + : WalletDatabase(), m_mock(mock), m_dir_path(dir_path.string()), m_file_path(file_path.string()) +{ + { + LOCK(g_sqlite_mutex); + LogPrintf("Using SQLite Version %s\n", SQLiteDatabaseVersion()); + LogPrintf("Using wallet %s\n", m_dir_path); + + if (++g_sqlite_count == 1) { + // Setup logging + int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret))); + } + // Force serialized threading mode + ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to configure serialized threading mode: %s\n", sqlite3_errstr(ret))); + } + } + int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret))); + } + } + + try { + Open(); + } catch (const std::runtime_error&) { + // If open fails, cleanup this object and rethrow the exception + Cleanup(); + throw; + } +} + +void SQLiteBatch::SetupSQLStatements() +{ + int res; + if (!m_read_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, "SELECT value FROM main WHERE key = ?", -1, &m_read_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res))); + } + } + if (!m_insert_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, "INSERT INTO main VALUES(?, ?)", -1, &m_insert_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res))); + } + } + if (!m_overwrite_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, "INSERT or REPLACE into main values(?, ?)", -1, &m_overwrite_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res))); + } + } + if (!m_delete_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, "DELETE FROM main WHERE key = ?", -1, &m_delete_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res))); + } + } + if (!m_cursor_stmt) { + if ((res = sqlite3_prepare_v2(m_database.m_db, "SELECT key, value FROM main", -1, &m_cursor_stmt, nullptr)) != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup SQL statements : %s\n", sqlite3_errstr(res))); + } + } +} + +SQLiteDatabase::~SQLiteDatabase() +{ + Cleanup(); +} + +void SQLiteDatabase::Cleanup() noexcept +{ + Close(); + + LOCK(g_sqlite_mutex); + if (--g_sqlite_count == 0) { + int ret = sqlite3_shutdown(); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteDatabase: Failed to shutdown SQLite: %s\n", sqlite3_errstr(ret)); + } + } +} + +bool SQLiteDatabase::Verify(bilingual_str& error) +{ + assert(m_db); + + // Check the application ID matches our network magic + sqlite3_stmt* app_id_stmt{nullptr}; + int ret = sqlite3_prepare_v2(m_db, "PRAGMA application_id", -1, &app_id_stmt, nullptr); + if (ret != SQLITE_OK) { + sqlite3_finalize(app_id_stmt); + error = strprintf(_("SQLiteDatabase: Failed to prepare the statement to fetch the application id: %s"), sqlite3_errstr(ret)); + return false; + } + ret = sqlite3_step(app_id_stmt); + if (ret != SQLITE_ROW) { + sqlite3_finalize(app_id_stmt); + error = strprintf(_("SQLiteDatabase: Failed to fetch the application id: %s"), sqlite3_errstr(ret)); + return false; + } + uint32_t app_id = static_cast<uint32_t>(sqlite3_column_int(app_id_stmt, 0)); + sqlite3_finalize(app_id_stmt); + uint32_t net_magic = ReadBE32(Params().MessageStart()); + if (app_id != net_magic) { + error = strprintf(_("SQLiteDatabase: Unexpected application id. Expected %u, got %u"), net_magic, app_id); + return false; + } + + // Check our schema version + sqlite3_stmt* user_ver_stmt{nullptr}; + ret = sqlite3_prepare_v2(m_db, "PRAGMA user_version", -1, &user_ver_stmt, nullptr); + if (ret != SQLITE_OK) { + sqlite3_finalize(user_ver_stmt); + error = strprintf(_("SQLiteDatabase: Failed to prepare the statement to fetch sqlite wallet schema version: %s"), sqlite3_errstr(ret)); + return false; + } + ret = sqlite3_step(user_ver_stmt); + if (ret != SQLITE_ROW) { + sqlite3_finalize(user_ver_stmt); + error = strprintf(_("SQLiteDatabase: Failed to fetch sqlite wallet schema version: %s"), sqlite3_errstr(ret)); + return false; + } + int32_t user_ver = sqlite3_column_int(user_ver_stmt, 0); + sqlite3_finalize(user_ver_stmt); + if (user_ver != WALLET_SCHEMA_VERSION) { + error = strprintf(_("SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported"), user_ver, WALLET_SCHEMA_VERSION); + return false; + } + + sqlite3_stmt* stmt{nullptr}; + ret = sqlite3_prepare_v2(m_db, "PRAGMA integrity_check", -1, &stmt, nullptr); + if (ret != SQLITE_OK) { + sqlite3_finalize(stmt); + error = strprintf(_("SQLiteDatabase: Failed to prepare statement to verify database: %s"), sqlite3_errstr(ret)); + return false; + } + while (true) { + ret = sqlite3_step(stmt); + if (ret == SQLITE_DONE) { + break; + } + if (ret != SQLITE_ROW) { + error = strprintf(_("SQLiteDatabase: Failed to execute statement to verify database: %s"), sqlite3_errstr(ret)); + break; + } + const char* msg = (const char*)sqlite3_column_text(stmt, 0); + if (!msg) { + error = strprintf(_("SQLiteDatabase: Failed to read database verification error: %s"), sqlite3_errstr(ret)); + break; + } + std::string str_msg(msg); + if (str_msg == "ok") { + continue; + } + if (error.empty()) { + error = _("Failed to verify database") + Untranslated("\n"); + } + error += Untranslated(strprintf("%s\n", str_msg)); + } + sqlite3_finalize(stmt); + return error.empty(); +} + +void SQLiteDatabase::Open() +{ + int flags = SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + if (m_mock) { + flags |= SQLITE_OPEN_MEMORY; // In memory database for mock db + } + + if (m_db == nullptr) { + if (!m_mock) { + TryCreateDirectories(m_dir_path); + } + int ret = sqlite3_open_v2(m_file_path.c_str(), &m_db, flags, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to open database: %s\n", sqlite3_errstr(ret))); + } + } + + if (sqlite3_db_readonly(m_db, "main") != 0) { + throw std::runtime_error("SQLiteDatabase: Database opened in readonly mode but read-write permissions are needed"); + } + + // Acquire an exclusive lock on the database + // First change the locking mode to exclusive + int ret = sqlite3_exec(m_db, "PRAGMA locking_mode = exclusive", nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Unable to change database locking mode to exclusive: %s\n", sqlite3_errstr(ret))); + } + // Now begin a transaction to acquire the exclusive lock. This lock won't be released until we close because of the exclusive locking mode. + ret = sqlite3_exec(m_db, "BEGIN EXCLUSIVE TRANSACTION", nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error("SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?\n"); + } + ret = sqlite3_exec(m_db, "COMMIT", nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Unable to end exclusive lock transaction: %s\n", sqlite3_errstr(ret))); + } + + // Enable fullfsync for the platforms that use it + ret = sqlite3_exec(m_db, "PRAGMA fullfsync = true", nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to enable fullfsync: %s\n", sqlite3_errstr(ret))); + } + + // Make the table for our key-value pairs + // First check that the main table exists + sqlite3_stmt* check_main_stmt{nullptr}; + ret = sqlite3_prepare_v2(m_db, "SELECT name FROM sqlite_master WHERE type='table' AND name='main'", -1, &check_main_stmt, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to prepare statement to check table existence: %s\n", sqlite3_errstr(ret))); + } + ret = sqlite3_step(check_main_stmt); + if (sqlite3_finalize(check_main_stmt) != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to finalize statement checking table existence: %s\n", sqlite3_errstr(ret))); + } + bool table_exists; + if (ret == SQLITE_DONE) { + table_exists = false; + } else if (ret == SQLITE_ROW) { + table_exists = true; + } else { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to execute statement to check table existence: %s\n", sqlite3_errstr(ret))); + } + + // Do the db setup things because the table doesn't exist only when we are creating a new wallet + if (!table_exists) { + ret = sqlite3_exec(m_db, "CREATE TABLE main(key BLOB PRIMARY KEY NOT NULL, value BLOB NOT NULL)", nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to create new database: %s\n", sqlite3_errstr(ret))); + } + + // Set the application id + uint32_t app_id = ReadBE32(Params().MessageStart()); + std::string set_app_id = strprintf("PRAGMA application_id = %d", static_cast<int32_t>(app_id)); + ret = sqlite3_exec(m_db, set_app_id.c_str(), nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to set the application id: %s\n", sqlite3_errstr(ret))); + } + + // Set the user version + std::string set_user_ver = strprintf("PRAGMA user_version = %d", WALLET_SCHEMA_VERSION); + ret = sqlite3_exec(m_db, set_user_ver.c_str(), nullptr, nullptr, nullptr); + if (ret != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to set the wallet schema version: %s\n", sqlite3_errstr(ret))); + } + } +} + +bool SQLiteDatabase::Rewrite(const char* skip) +{ + // Rewrite the database using the VACUUM command: https://sqlite.org/lang_vacuum.html + int ret = sqlite3_exec(m_db, "VACUUM", nullptr, nullptr, nullptr); + return ret == SQLITE_OK; +} + +bool SQLiteDatabase::Backup(const std::string& dest) const +{ + sqlite3* db_copy; + int res = sqlite3_open(dest.c_str(), &db_copy); + if (res != SQLITE_OK) { + sqlite3_close(db_copy); + return false; + } + sqlite3_backup* backup = sqlite3_backup_init(db_copy, "main", m_db, "main"); + if (!backup) { + LogPrintf("%s: Unable to begin backup: %s\n", __func__, sqlite3_errmsg(m_db)); + sqlite3_close(db_copy); + return false; + } + // Specifying -1 will copy all of the pages + res = sqlite3_backup_step(backup, -1); + if (res != SQLITE_DONE) { + LogPrintf("%s: Unable to backup: %s\n", __func__, sqlite3_errstr(res)); + sqlite3_backup_finish(backup); + sqlite3_close(db_copy); + return false; + } + res = sqlite3_backup_finish(backup); + sqlite3_close(db_copy); + return res == SQLITE_OK; +} + +void SQLiteDatabase::Close() +{ + int res = sqlite3_close(m_db); + if (res != SQLITE_OK) { + throw std::runtime_error(strprintf("SQLiteDatabase: Failed to close database: %s\n", sqlite3_errstr(res))); + } + m_db = nullptr; +} + +std::unique_ptr<DatabaseBatch> SQLiteDatabase::MakeBatch(bool flush_on_close) +{ + // We ignore flush_on_close because we don't do manual flushing for SQLite + return MakeUnique<SQLiteBatch>(*this); +} + +SQLiteBatch::SQLiteBatch(SQLiteDatabase& database) + : m_database(database) +{ + // Make sure we have a db handle + assert(m_database.m_db); + + SetupSQLStatements(); +} + +void SQLiteBatch::Close() +{ + // If m_db is in a transaction (i.e. not in autocommit mode), then abort the transaction in progress + if (m_database.m_db && sqlite3_get_autocommit(m_database.m_db) == 0) { + if (TxnAbort()) { + LogPrintf("SQLiteBatch: Batch closed unexpectedly without the transaction being explicitly committed or aborted\n"); + } else { + LogPrintf("SQLiteBatch: Batch closed and failed to abort transaction\n"); + } + } + + // Free all of the prepared statements + int ret = sqlite3_finalize(m_read_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize read statement: %s\n", sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_insert_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize insert statement: %s\n", sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_overwrite_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize overwrite statement: %s\n", sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_delete_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize delete statement: %s\n", sqlite3_errstr(ret)); + } + ret = sqlite3_finalize(m_cursor_stmt); + if (ret != SQLITE_OK) { + LogPrintf("SQLiteBatch: Batch closed but could not finalize cursor statement: %s\n", sqlite3_errstr(ret)); + } + m_read_stmt = nullptr; + m_insert_stmt = nullptr; + m_overwrite_stmt = nullptr; + m_delete_stmt = nullptr; + m_cursor_stmt = nullptr; +} + +bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value) +{ + if (!m_database.m_db) return false; + assert(m_read_stmt); + + // Bind: leftmost parameter in statement is index 1 + int res = sqlite3_bind_blob(m_read_stmt, 1, key.data(), key.size(), SQLITE_STATIC); + if (res != SQLITE_OK) { + LogPrintf("%s: Unable to bind statement: %s\n", __func__, sqlite3_errstr(res)); + sqlite3_clear_bindings(m_read_stmt); + sqlite3_reset(m_read_stmt); + return false; + } + res = sqlite3_step(m_read_stmt); + if (res != SQLITE_ROW) { + if (res != SQLITE_DONE) { + // SQLITE_DONE means "not found", don't log an error in that case. + LogPrintf("%s: Unable to execute statement: %s\n", __func__, sqlite3_errstr(res)); + } + sqlite3_clear_bindings(m_read_stmt); + sqlite3_reset(m_read_stmt); + return false; + } + // Leftmost column in result is index 0 + const char* data = reinterpret_cast<const char*>(sqlite3_column_blob(m_read_stmt, 0)); + int data_size = sqlite3_column_bytes(m_read_stmt, 0); + value.write(data, data_size); + + sqlite3_clear_bindings(m_read_stmt); + sqlite3_reset(m_read_stmt); + return true; +} + +bool SQLiteBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite) +{ + if (!m_database.m_db) return false; + assert(m_insert_stmt && m_overwrite_stmt); + + sqlite3_stmt* stmt; + if (overwrite) { + stmt = m_overwrite_stmt; + } else { + stmt = m_insert_stmt; + } + + // Bind: leftmost parameter in statement is index 1 + // Insert index 1 is key, 2 is value + int res = sqlite3_bind_blob(stmt, 1, key.data(), key.size(), SQLITE_STATIC); + if (res != SQLITE_OK) { + LogPrintf("%s: Unable to bind key to statement: %s\n", __func__, sqlite3_errstr(res)); + sqlite3_clear_bindings(stmt); + sqlite3_reset(stmt); + return false; + } + res = sqlite3_bind_blob(stmt, 2, value.data(), value.size(), SQLITE_STATIC); + if (res != SQLITE_OK) { + LogPrintf("%s: Unable to bind value to statement: %s\n", __func__, sqlite3_errstr(res)); + sqlite3_clear_bindings(stmt); + sqlite3_reset(stmt); + return false; + } + + // Execute + res = sqlite3_step(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_reset(stmt); + if (res != SQLITE_DONE) { + LogPrintf("%s: Unable to execute statement: %s\n", __func__, sqlite3_errstr(res)); + } + return res == SQLITE_DONE; +} + +bool SQLiteBatch::EraseKey(CDataStream&& key) +{ + if (!m_database.m_db) return false; + assert(m_delete_stmt); + + // Bind: leftmost parameter in statement is index 1 + int res = sqlite3_bind_blob(m_delete_stmt, 1, key.data(), key.size(), SQLITE_STATIC); + if (res != SQLITE_OK) { + LogPrintf("%s: Unable to bind statement: %s\n", __func__, sqlite3_errstr(res)); + sqlite3_clear_bindings(m_delete_stmt); + sqlite3_reset(m_delete_stmt); + return false; + } + + // Execute + res = sqlite3_step(m_delete_stmt); + sqlite3_clear_bindings(m_delete_stmt); + sqlite3_reset(m_delete_stmt); + if (res != SQLITE_DONE) { + LogPrintf("%s: Unable to execute statement: %s\n", __func__, sqlite3_errstr(res)); + } + return res == SQLITE_DONE; +} + +bool SQLiteBatch::HasKey(CDataStream&& key) +{ + if (!m_database.m_db) return false; + assert(m_read_stmt); + + // Bind: leftmost parameter in statement is index 1 + bool ret = false; + int res = sqlite3_bind_blob(m_read_stmt, 1, key.data(), key.size(), SQLITE_STATIC); + if (res == SQLITE_OK) { + res = sqlite3_step(m_read_stmt); + if (res == SQLITE_ROW) { + ret = true; + } + } + + sqlite3_clear_bindings(m_read_stmt); + sqlite3_reset(m_read_stmt); + return ret; +} + +bool SQLiteBatch::StartCursor() +{ + assert(!m_cursor_init); + if (!m_database.m_db) return false; + m_cursor_init = true; + return true; +} + +bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete) +{ + complete = false; + + if (!m_cursor_init) return false; + + int res = sqlite3_step(m_cursor_stmt); + if (res == SQLITE_DONE) { + complete = true; + return true; + } + if (res != SQLITE_ROW) { + LogPrintf("SQLiteBatch::ReadAtCursor: Unable to execute cursor step: %s\n", sqlite3_errstr(res)); + return false; + } + + // Leftmost column in result is index 0 + const char* key_data = reinterpret_cast<const char*>(sqlite3_column_blob(m_cursor_stmt, 0)); + int key_data_size = sqlite3_column_bytes(m_cursor_stmt, 0); + key.write(key_data, key_data_size); + const char* value_data = reinterpret_cast<const char*>(sqlite3_column_blob(m_cursor_stmt, 1)); + int value_data_size = sqlite3_column_bytes(m_cursor_stmt, 1); + value.write(value_data, value_data_size); + return true; +} + +void SQLiteBatch::CloseCursor() +{ + sqlite3_reset(m_cursor_stmt); + m_cursor_init = false; +} + +bool SQLiteBatch::TxnBegin() +{ + if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) == 0) return false; + int res = sqlite3_exec(m_database.m_db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr); + if (res != SQLITE_OK) { + LogPrintf("SQLiteBatch: Failed to begin the transaction\n"); + } + return res == SQLITE_OK; +} + +bool SQLiteBatch::TxnCommit() +{ + if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) != 0) return false; + int res = sqlite3_exec(m_database.m_db, "COMMIT TRANSACTION", nullptr, nullptr, nullptr); + if (res != SQLITE_OK) { + LogPrintf("SQLiteBatch: Failed to commit the transaction\n"); + } + return res == SQLITE_OK; +} + +bool SQLiteBatch::TxnAbort() +{ + if (!m_database.m_db || sqlite3_get_autocommit(m_database.m_db) != 0) return false; + int res = sqlite3_exec(m_database.m_db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr); + if (res != SQLITE_OK) { + LogPrintf("SQLiteBatch: Failed to abort the transaction\n"); + } + return res == SQLITE_OK; +} + +std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error) +{ + try { + fs::path data_file = SQLiteDataFile(path); + auto db = MakeUnique<SQLiteDatabase>(data_file.parent_path(), data_file); + if (options.verify && !db->Verify(error)) { + status = DatabaseStatus::FAILED_VERIFY; + return nullptr; + } + status = DatabaseStatus::SUCCESS; + return db; + } catch (const std::runtime_error& e) { + status = DatabaseStatus::FAILED_LOAD; + error = Untranslated(e.what()); + return nullptr; + } +} + +std::string SQLiteDatabaseVersion() +{ + return std::string(sqlite3_libversion()); +} diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h new file mode 100644 index 0000000000..70ab4f797a --- /dev/null +++ b/src/wallet/sqlite.h @@ -0,0 +1,120 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_SQLITE_H +#define BITCOIN_WALLET_SQLITE_H + +#include <wallet/db.h> + +#include <sqlite3.h> + +struct bilingual_str; +class SQLiteDatabase; + +/** RAII class that provides access to a WalletDatabase */ +class SQLiteBatch : public DatabaseBatch +{ +private: + SQLiteDatabase& m_database; + + bool m_cursor_init = false; + + sqlite3_stmt* m_read_stmt{nullptr}; + sqlite3_stmt* m_insert_stmt{nullptr}; + sqlite3_stmt* m_overwrite_stmt{nullptr}; + sqlite3_stmt* m_delete_stmt{nullptr}; + sqlite3_stmt* m_cursor_stmt{nullptr}; + + void SetupSQLStatements(); + + bool ReadKey(CDataStream&& key, CDataStream& value) override; + bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite = true) override; + bool EraseKey(CDataStream&& key) override; + bool HasKey(CDataStream&& key) override; + +public: + explicit SQLiteBatch(SQLiteDatabase& database); + ~SQLiteBatch() override { Close(); } + + /* No-op. See comment on SQLiteDatabase::Flush */ + void Flush() override {} + + void Close() override; + + bool StartCursor() override; + bool ReadAtCursor(CDataStream& key, CDataStream& value, bool& complete) override; + void CloseCursor() override; + bool TxnBegin() override; + bool TxnCommit() override; + bool TxnAbort() override; +}; + +/** An instance of this class represents one SQLite3 database. + **/ +class SQLiteDatabase : public WalletDatabase +{ +private: + const bool m_mock{false}; + + const std::string m_dir_path; + + const std::string m_file_path; + + void Cleanup() noexcept; + +public: + SQLiteDatabase() = delete; + + /** Create DB handle to real database */ + SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, bool mock = false); + + ~SQLiteDatabase(); + + bool Verify(bilingual_str& error); + + /** Open the database if it is not already opened */ + void Open() override; + + /** Close the database */ + void Close() override; + + /* These functions are unused */ + void AddRef() override { assert(false); } + void RemoveRef() override { assert(false); } + + /** Rewrite the entire database on disk */ + bool Rewrite(const char* skip = nullptr) override; + + /** Back up the entire database to a file. + */ + bool Backup(const std::string& dest) const override; + + /** No-ops + * + * SQLite always flushes everything to the database file after each transaction + * (each Read/Write/Erase that we do is its own transaction unless we called + * TxnBegin) so there is no need to have Flush or Periodic Flush. + * + * There is no DB env to reload, so ReloadDbEnv has nothing to do + */ + void Flush() override {} + bool PeriodicFlush() override { return false; } + void ReloadDbEnv() override {} + + void IncrementUpdateCounter() override { ++nUpdateCounter; } + + std::string Filename() override { return m_file_path; } + std::string Format() override { return "sqlite"; } + + /** Make a SQLiteBatch connected to this database */ + std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override; + + sqlite3* m_db{nullptr}; +}; + +std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); + +std::string SQLiteDatabaseVersion(); + +#endif // BITCOIN_WALLET_SQLITE_H diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index b5c9e62b5c..ffac78d752 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -64,7 +64,8 @@ static void add_coin(CWallet& wallet, const CAmount& nValue, int nAge = 6*24, bo if (spendable) { CTxDestination dest; std::string error; - assert(wallet.GetNewDestination(OutputType::BECH32, "", dest, error)); + const bool destination_ok = wallet.GetNewDestination(OutputType::BECH32, "", dest, error); + assert(destination_ok); tx.vout[nInput].scriptPubKey = GetScriptForDestination(dest); } if (fIsFromMe) { @@ -289,7 +290,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) // Make sure that can use BnB when there are preset inputs empty_wallet(); { - std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_chain.get(), "", CreateMockWalletDatabase()); + std::unique_ptr<CWallet> wallet = MakeUnique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase()); bool firstRun; wallet->LoadWallet(firstRun); wallet->SetupLegacyScriptPubKeyMan(); @@ -458,7 +459,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test) BOOST_CHECK( testWallet.SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)); BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount - // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) + // run the 'mtgox' test (see https://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) // they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change empty_wallet(); for (int j = 0; j < 20; j++) diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index 8f0083cd2e..27179839b7 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,6 +13,13 @@ BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup) +static std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& path, std::string& database_filename) +{ + fs::path data_file = BDBDataFile(path); + database_filename = data_file.filename().string(); + return GetBerkeleyEnv(data_file.parent_path()); +} + BOOST_AUTO_TEST_CASE(getwalletenv_file) { std::string test_name = "test_name.dat"; diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp index c80310045a..f035a70a20 100644 --- a/src/wallet/test/init_test_fixture.cpp +++ b/src/wallet/test/init_test_fixture.cpp @@ -1,8 +1,9 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <fs.h> +#include <univalue.h> #include <util/check.h> #include <util/system.h> @@ -10,7 +11,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) { - m_wallet_client = MakeWalletClient(*m_chain, *Assert(m_node.args)); + m_wallet_client = MakeWalletClient(*m_node.chain, *Assert(m_node.args)); std::string sep; sep += fs::path::preferred_separator; @@ -37,6 +38,9 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam InitWalletDirTestingSetup::~InitWalletDirTestingSetup() { + gArgs.LockSettings([&](util::Settings& settings) { + settings.forced_settings.erase("walletdir"); + }); fs::current_path(m_cwd); } diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h index f5bade77df..37ae907de5 100644 --- a/src/wallet/test/init_test_fixture.h +++ b/src/wallet/test/init_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,7 +19,6 @@ struct InitWalletDirTestingSetup: public BasicTestingSetup { fs::path m_datadir; fs::path m_cwd; std::map<std::string, fs::path> m_walletdir_path_cases; - std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(m_node); std::unique_ptr<interfaces::WalletClient> m_wallet_client; }; diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index 9b905569fc..e70b56c529 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp index d5aed99d99..5d25885bd4 100644 --- a/src/wallet/test/ismine_tests.cpp +++ b/src/wallet/test/ismine_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -27,8 +27,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard) CKey uncompressedKey; uncompressedKey.MakeNewKey(false); CPubKey uncompressedPubkey = uncompressedKey.GetPubKey(); - NodeContext node; - std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node); + std::unique_ptr<interfaces::Chain>& chain = m_node.chain; CScript scriptPubKey; isminetype result; diff --git a/src/wallet/test/scriptpubkeyman_tests.cpp b/src/wallet/test/scriptpubkeyman_tests.cpp index f7c1337b0d..347a436429 100644 --- a/src/wallet/test/scriptpubkeyman_tests.cpp +++ b/src/wallet/test/scriptpubkeyman_tests.cpp @@ -17,9 +17,7 @@ BOOST_FIXTURE_TEST_SUITE(scriptpubkeyman_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(CanProvide) { // Set up wallet and keyman variables. - NodeContext node; - std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain(node); - CWallet wallet(chain.get(), "", CreateDummyWalletDatabase()); + CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase()); LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan(); // Make a 1 of 2 multisig script diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index 10ddfa22ef..5b421840e0 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 4d6f427618..badf2eb459 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -6,10 +6,10 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName) : TestingSetup(chainName), - m_wallet(m_chain.get(), "", CreateMockWalletDatabase()) + m_wallet(m_node.chain.get(), "", CreateMockWalletDatabase()) { bool fFirstRun; m_wallet.LoadWallet(fFirstRun); - m_chain_notifications_handler = m_chain->handleNotifications({ &m_wallet, [](CWallet*) {} }); + m_chain_notifications_handler = m_node.chain->handleNotifications({ &m_wallet, [](CWallet*) {} }); m_wallet_client->registerRpcs(); } diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index ba8a5ff1f3..ab7fb8c42b 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -20,8 +20,7 @@ struct WalletTestingSetup : public TestingSetup { explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); - std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(m_node); - std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_chain, *Assert(m_node.args)); + std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_node.chain, *Assert(m_node.args)); CWallet m_wallet; std::unique_ptr<interfaces::Handler> m_chain_notifications_handler; }; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 4393bb7701..5480f3ab22 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -28,6 +28,8 @@ RPCHelpMan importmulti(); RPCHelpMan dumpwallet(); RPCHelpMan importwallet(); +extern RecursiveMutex cs_wallets; + // Ensure that fee levels defined in the wallet are at least as high // as the default levels for node policy. static_assert(DEFAULT_TRANSACTION_MINFEE >= DEFAULT_MIN_RELAY_TX_FEE, "wallet minimum fee is smaller than default relay fee"); @@ -83,12 +85,9 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = ::ChainActive().Tip(); - NodeContext node; - auto chain = interfaces::MakeChain(node); - // Verify ScanForWalletTransactions fails to read an unknown start block. { - CWallet wallet(chain.get(), "", CreateDummyWalletDatabase()); + CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase()); { LOCK(wallet.cs_wallet); wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); @@ -107,7 +106,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) // Verify ScanForWalletTransactions picks up transactions in both the old // and new block files. { - CWallet wallet(chain.get(), "", CreateDummyWalletDatabase()); + CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase()); { LOCK(wallet.cs_wallet); wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); @@ -133,7 +132,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) // Verify ScanForWalletTransactions only picks transactions in the new block // file. { - CWallet wallet(chain.get(), "", CreateDummyWalletDatabase()); + CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase()); { LOCK(wallet.cs_wallet); wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); @@ -158,7 +157,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) // Verify ScanForWalletTransactions scans no blocks. { - CWallet wallet(chain.get(), "", CreateDummyWalletDatabase()); + CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase()); { LOCK(wallet.cs_wallet); wallet.SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); @@ -183,9 +182,6 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = ::ChainActive().Tip(); - NodeContext node; - auto chain = interfaces::MakeChain(node); - // Prune the older block file. { LOCK(cs_main); @@ -197,7 +193,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) // before the missing block, and success for a key whose creation time is // after. { - std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase()); + std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase()); wallet->SetupLegacyScriptPubKeyMan(); WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(newTip->nHeight, newTip->GetBlockHash())); AddWallet(wallet); @@ -255,14 +251,11 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) SetMockTime(KEY_TIME); m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); - NodeContext node; - auto chain = interfaces::MakeChain(node); - std::string backup_file = (GetDataDir() / "wallet.backup").string(); // Import key into wallet and call dumpwallet to create backup file. { - std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase()); + std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase()); { auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan(); LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore); @@ -284,7 +277,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) // Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME // were scanned, and no prior blocks were scanned. { - std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase()); + std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase()); LOCK(wallet->cs_wallet); wallet->SetupLegacyScriptPubKeyMan(); @@ -317,10 +310,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) // debit functions. BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup) { - NodeContext node; - auto chain = interfaces::MakeChain(node); - - CWallet wallet(chain.get(), "", CreateDummyWalletDatabase()); + CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase()); auto spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan(); CWalletTx wtx(&wallet, m_coinbase_txns.back()); @@ -495,7 +485,7 @@ public: ListCoinsTestingSetup() { CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); - wallet = MakeUnique<CWallet>(m_chain.get(), "", CreateMockWalletDatabase()); + wallet = MakeUnique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase()); { LOCK2(wallet->cs_wallet, ::cs_main); wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); @@ -524,8 +514,9 @@ public: int changePos = -1; bilingual_str error; CCoinControl dummy; + FeeCalculation fee_calc_out; { - BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, fee, changePos, error, dummy)); + BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, fee, changePos, error, dummy, fee_calc_out)); } wallet->CommitTransaction(tx, {}, {}); CMutableTransaction blocktx; @@ -544,7 +535,6 @@ public: return it->second; } - std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain(m_node); std::unique_ptr<CWallet> wallet; }; @@ -560,7 +550,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) list = wallet->ListCoins(); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U); // Check initial balance from one mature coinbase transaction. @@ -576,7 +566,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) list = wallet->ListCoins(); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); // Lock both coins. Confirm number of available coins drops to 0. @@ -605,15 +595,13 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup) list = wallet->ListCoins(); } BOOST_CHECK_EQUAL(list.size(), 1U); - BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); + BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress); BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U); } BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup) { - NodeContext node; - auto chain = interfaces::MakeChain(node); - std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase()); + std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase()); wallet->SetupLegacyScriptPubKeyMan(); wallet->SetMinVersion(FEATURE_LATEST); wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); @@ -687,7 +675,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup) BOOST_CHECK_EXCEPTION(vr >> w_desc, std::ios_base::failure, malformed_descriptor); } -//! Test CreateWalletFromFile function and its behavior handling potential race +//! Test CWallet::Create() and its behavior handling potential race //! conditions if it's called the same time an incoming transaction shows up in //! the mempool or a new block. //! @@ -705,11 +693,10 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup) //! wallet rescan and notifications are immediately synced, to verify the wallet //! must already have a handler in place for them, and there's no gap after //! rescanning where new transactions in new blocks could be lost. -BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup) +BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup) { // Create new wallet with known key and unload it. - auto chain = interfaces::MakeChain(m_node); - auto wallet = TestLoadWallet(*chain); + auto wallet = TestLoadWallet(*m_node.chain); CKey key; key.MakeNewKey(true); AddKey(*wallet, key); @@ -744,12 +731,12 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup) auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); auto mempool_tx = TestSimpleSpend(*m_coinbase_txns[1], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); - BOOST_CHECK(chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error)); + BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error)); // Reload wallet and make sure new transactions are detected despite events // being blocked - wallet = TestLoadWallet(*chain); + wallet = TestLoadWallet(*m_node.chain); BOOST_CHECK(rescan_completed); BOOST_CHECK_EQUAL(addtx_count, 2); { @@ -776,18 +763,20 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup) // deadlock during the sync and simulates a new block notification happening // as soon as possible. addtx_count = 0; - auto handler = HandleLoadWallet([&](std::unique_ptr<interfaces::Wallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->wallet()->cs_wallet) { + auto handler = HandleLoadWallet([&](std::unique_ptr<interfaces::Wallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->wallet()->cs_wallet, cs_wallets) { BOOST_CHECK(rescan_completed); m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); - BOOST_CHECK(chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error)); + BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error)); + LEAVE_CRITICAL_SECTION(cs_wallets); LEAVE_CRITICAL_SECTION(wallet->wallet()->cs_wallet); SyncWithValidationInterfaceQueue(); ENTER_CRITICAL_SECTION(wallet->wallet()->cs_wallet); + ENTER_CRITICAL_SECTION(cs_wallets); }); - wallet = TestLoadWallet(*chain); + wallet = TestLoadWallet(*m_node.chain); BOOST_CHECK_EQUAL(addtx_count, 4); { LOCK(wallet->cs_wallet); @@ -801,8 +790,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWalletFromFile, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup) { - auto chain = interfaces::MakeChain(m_node); - auto wallet = TestLoadWallet(*chain); + auto wallet = TestLoadWallet(*m_node.chain); CKey key; key.MakeNewKey(true); AddKey(*wallet, key); diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp new file mode 100644 index 0000000000..558121ae42 --- /dev/null +++ b/src/wallet/test/walletdb_tests.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2012-2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <test/util/setup_common.h> +#include <clientversion.h> +#include <streams.h> +#include <uint256.h> + +#include <boost/test/unit_test.hpp> + +BOOST_FIXTURE_TEST_SUITE(walletdb_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(walletdb_readkeyvalue) +{ + /** + * When ReadKeyValue() reads from either a "key" or "wkey" it first reads the CDataStream steam into a + * CPrivKey or CWalletKey respectively and then reads a hash of the pubkey and privkey into a uint256. + * Wallets from 0.8 or before do not store the pubkey/privkey hash, trying to read the hash from old + * wallets throws an exception, for backwards compatibility this read is wrapped in a try block to + * silently fail. The test here makes sure the type of exception thrown from CDataStream::read() + * matches the type we expect, otherwise we need to update the "key"/"wkey" exception type caught. + */ + CDataStream ssValue(SER_DISK, CLIENT_VERSION); + uint256 dummy; + BOOST_CHECK_THROW(ssValue >> dummy, std::ios_base::failure); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8ab9438f8c..db80745db0 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -52,7 +52,7 @@ const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS{ static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10; -static RecursiveMutex cs_wallets; +RecursiveMutex cs_wallets; static std::vector<std::shared_ptr<CWallet>> vpwallets GUARDED_BY(cs_wallets); static std::list<LoadWalletFn> g_load_wallet_fns GUARDED_BY(cs_wallets); @@ -85,9 +85,9 @@ static void UpdateWalletSetting(interfaces::Chain& chain, std::vector<bilingual_str>& warnings) { if (load_on_startup == nullopt) return; - if (load_on_startup.get() && !AddWalletSetting(chain, wallet_name)) { + if (load_on_startup.value() && !AddWalletSetting(chain, wallet_name)) { warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup.")); - } else if (!load_on_startup.get() && !RemoveWalletSetting(chain, wallet_name)) { + } else if (!load_on_startup.value() && !RemoveWalletSetting(chain, wallet_name)) { warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup.")); } } @@ -100,6 +100,7 @@ bool AddWallet(const std::shared_ptr<CWallet>& wallet) if (i != vpwallets.end()) return false; vpwallets.push_back(wallet); wallet->ConnectScriptPubKeyManNotifiers(); + wallet->NotifyCanGetAddressesChanged(); return true; } @@ -243,11 +244,13 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& return wallet; } -std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) +std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) { uint64_t wallet_creation_flags = options.create_flags; const SecureString& passphrase = options.create_passphrase; + if (wallet_creation_flags & WALLET_FLAG_DESCRIPTORS) options.require_format = DatabaseFormat::SQLITE; + // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET); @@ -416,7 +419,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey)) return false; - WalletBatch(*database).WriteMasterKey(pMasterKey.first, pMasterKey.second); + WalletBatch(GetDatabase()).WriteMasterKey(pMasterKey.first, pMasterKey.second); if (fWasLocked) Lock(); return true; @@ -429,27 +432,19 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, void CWallet::chainStateFlushed(const CBlockLocator& loc) { - WalletBatch batch(*database); + WalletBatch batch(GetDatabase()); batch.WriteBestBlock(loc); } -void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in, bool fExplicit) +void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in) { LOCK(cs_wallet); if (nWalletVersion >= nVersion) return; - - // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way - if (fExplicit && nVersion > nWalletMaxVersion) - nVersion = FEATURE_LATEST; - nWalletVersion = nVersion; - if (nVersion > nWalletMaxVersion) - nWalletMaxVersion = nVersion; - { - WalletBatch* batch = batch_in ? batch_in : new WalletBatch(*database); + WalletBatch* batch = batch_in ? batch_in : new WalletBatch(GetDatabase()); if (nWalletVersion > 40000) batch->WriteMinVersion(nWalletVersion); if (!batch_in) @@ -457,18 +452,6 @@ void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in, } } -bool CWallet::SetMaxVersion(int nVersion) -{ - LOCK(cs_wallet); - // cannot downgrade below current version - if (nWalletVersion > nVersion) - return false; - - nWalletMaxVersion = nVersion; - - return true; -} - std::set<uint256> CWallet::GetConflicts(const uint256& txid) const { std::set<uint256> result; @@ -501,12 +484,12 @@ bool CWallet::HasWalletSpend(const uint256& txid) const void CWallet::Flush() { - database->Flush(); + GetDatabase().Flush(); } void CWallet::Close() { - database->Close(); + GetDatabase().Close(); } void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range) @@ -587,7 +570,7 @@ void CWallet::AddToSpends(const uint256& wtxid) { auto it = mapWallet.find(wtxid); assert(it != mapWallet.end()); - CWalletTx& thisTx = it->second; + const CWalletTx& thisTx = it->second; if (thisTx.IsCoinBase()) // Coinbases don't spend anything! return; @@ -632,7 +615,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { LOCK(cs_wallet); mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; - WalletBatch* encrypted_batch = new WalletBatch(*database); + WalletBatch* encrypted_batch = new WalletBatch(GetDatabase()); if (!encrypted_batch->TxnBegin()) { delete encrypted_batch; encrypted_batch = nullptr; @@ -653,7 +636,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) } // Encryption was introduced in version 0.4.0 - SetMinVersion(FEATURE_WALLETCRYPT, encrypted_batch, true); + SetMinVersion(FEATURE_WALLETCRYPT, encrypted_batch); if (!encrypted_batch->TxnCommit()) { delete encrypted_batch; @@ -684,12 +667,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) // Need to completely rewrite the wallet file; if we don't, bdb might keep // bits of the unencrypted private key in slack space in the database file. - database->Rewrite(); + GetDatabase().Rewrite(); // BDB seems to have a bad habit of writing old data into // slack space in .dat files; that is bad if the old data is // unencrypted private keys. So: - database->ReloadDbEnv(); + GetDatabase().ReloadDbEnv(); } NotifyStatusChanged(this); @@ -700,7 +683,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) DBErrors CWallet::ReorderTransactions() { LOCK(cs_wallet); - WalletBatch batch(*database); + WalletBatch batch(GetDatabase()); // Old wallets didn't have any defined order for transactions // Probably a bad idea to change the output of this @@ -761,7 +744,7 @@ int64_t CWallet::IncOrderPosNext(WalletBatch* batch) if (batch) { batch->WriteOrderPosNext(nOrderPosNext); } else { - WalletBatch(*database).WriteOrderPosNext(nOrderPosNext); + WalletBatch(GetDatabase()).WriteOrderPosNext(nOrderPosNext); } return nRet; } @@ -791,7 +774,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash) wtx.mapValue["replaced_by_txid"] = newHash.ToString(); - WalletBatch batch(*database, "r+"); + WalletBatch batch(GetDatabase()); bool success = true; if (!batch.WriteTx(wtx)) { @@ -863,7 +846,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio { LOCK(cs_wallet); - WalletBatch batch(*database, "r+", fFlushOnClose); + WalletBatch batch(GetDatabase(), fFlushOnClose); uint256 hash = tx->GetHash(); @@ -963,11 +946,12 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx } // If wallet doesn't have a chain (e.g wallet-tool), don't bother to update txn. if (HaveChain()) { - Optional<int> block_height = chain().getBlockHeight(wtx.m_confirm.hashBlock); - if (block_height) { + bool active; + int height; + if (chain().findBlock(wtx.m_confirm.hashBlock, FoundBlock().inActiveChain(active).height(height)) && active) { // Update cached block height variable since it not stored in the // serialized transaction. - wtx.m_confirm.block_height = *block_height; + wtx.m_confirm.block_height = height; } else if (wtx.isConflicted() || wtx.isConfirmed()) { // If tx block (or conflicting block) was reorged out of chain // while the wallet was shutdown, change tx status to UNCONFIRMED @@ -1062,7 +1046,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) { LOCK(cs_wallet); - WalletBatch batch(*database, "r+"); + WalletBatch batch(GetDatabase()); std::set<uint256> todo; std::set<uint256> done; @@ -1070,7 +1054,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx) // Can't mark abandoned if confirmed or in mempool auto it = mapWallet.find(hashTx); assert(it != mapWallet.end()); - CWalletTx& origtx = it->second; + const CWalletTx& origtx = it->second; if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) { return false; } @@ -1125,7 +1109,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c return; // Do not flush the wallet here for performance reasons - WalletBatch batch(*database, "r+", false); + WalletBatch batch(GetDatabase(), false); std::set<uint256> todo; std::set<uint256> done; @@ -1194,9 +1178,8 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe // Handle transactions that were removed from the mempool because they // conflict with transactions in a newly connected block. if (reason == MemPoolRemovalReason::CONFLICT) { - // Call SyncNotifications, so external -walletnotify notifications will - // be triggered for these transactions. Set Status::UNCONFIRMED instead - // of Status::CONFLICTED for a few reasons: + // Trigger external -walletnotify notifications for these transactions. + // Set Status::UNCONFIRMED instead of Status::CONFLICTED for a few reasons: // // 1. The transactionRemovedFromMempool callback does not currently // provide the conflicting block's hash and height, and for backwards @@ -1463,13 +1446,13 @@ void CWallet::SetWalletFlag(uint64_t flags) { LOCK(cs_wallet); m_wallet_flags |= flags; - if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags)) + if (!WalletBatch(GetDatabase()).WriteWalletFlags(m_wallet_flags)) throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); } void CWallet::UnsetWalletFlag(uint64_t flag) { - WalletBatch batch(*database); + WalletBatch batch(GetDatabase()); UnsetWalletFlagWithDB(batch, flag); } @@ -1508,7 +1491,7 @@ bool CWallet::AddWalletFlags(uint64_t flags) LOCK(cs_wallet); // We should never be writing unknown non-tolerable wallet flags assert(((flags & KNOWN_WALLET_FLAGS) >> 32) == (flags >> 32)); - if (!WalletBatch(*database).WriteWalletFlags(flags)) { + if (!WalletBatch(GetDatabase()).WriteWalletFlags(flags)) { throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); } @@ -1599,7 +1582,7 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri return false; } if (apply_label) { - WalletBatch batch(*database); + WalletBatch batch(GetDatabase()); for (const CScript& script : script_pub_keys) { CTxDestination dest; ExtractDestination(script, dest); @@ -1775,7 +1758,11 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc double progress_current = progress_begin; int block_height = start_height; while (!fAbortRescan && !chain().shutdownRequested()) { - m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin); + if (progress_end - progress_begin > 0.0) { + m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin); + } else { // avoid divide-by-zero for single block scan range (i.e. start and stop hashes are equal) + m_scanning_progress = 0; + } if (block_height % 100 == 0 && progress_end - progress_begin > 0.0) { ShowProgress(strprintf("%s " + _("Rescanning...").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100)))); } @@ -1784,18 +1771,22 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", block_height, progress_current); } + // Read block data CBlock block; - bool next_block; + chain().findBlock(block_hash, FoundBlock().data(block)); + + // Find next block separately from reading data above, because reading + // is slow and there might be a reorg while it is read. + bool block_still_active = false; + bool next_block = false; uint256 next_block_hash; - bool reorg = false; - if (chain().findBlock(block_hash, FoundBlock().data(block)) && !block.IsNull()) { + chain().findBlock(block_hash, FoundBlock().inActiveChain(block_still_active).nextBlock(FoundBlock().inActiveChain(next_block).hash(next_block_hash))); + + if (!block.IsNull()) { LOCK(cs_wallet); - next_block = chain().findNextBlock(block_hash, block_height, FoundBlock().hash(next_block_hash), &reorg); - if (reorg) { + if (!block_still_active) { // Abort scan if current block is no longer active, to prevent // marking transactions as coming from the wrong block. - // TODO: This should return success instead of failure, see - // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518 result.last_failed_block = block_hash; result.status = ScanResult::FAILURE; break; @@ -1810,13 +1801,12 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc // could not scan block, keep scanning but record this block as the most recent failure result.last_failed_block = block_hash; result.status = ScanResult::FAILURE; - next_block = chain().findNextBlock(block_hash, block_height, FoundBlock().hash(next_block_hash), &reorg); } if (max_height && block_height >= *max_height) { break; } { - if (!next_block || reorg) { + if (!next_block) { // break successfully when rescan has reached the tip, or // previous block is no longer on the chain due to a reorg break; @@ -2618,7 +2608,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC LOCK(cs_wallet); CTransactionRef tx_new; - if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, false)) { + FeeCalculation fee_calc_out; + if (!CreateTransaction(vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, fee_calc_out, false)) { return false; } @@ -2707,7 +2698,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uin return locktime; } -OutputType CWallet::TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) +OutputType CWallet::TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const { // If -changetype is specified, always use that change type. if (change_type) { @@ -2742,6 +2733,7 @@ bool CWallet::CreateTransactionInternal( int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, + FeeCalculation& fee_calc_out, bool sign) { CAmount nValue = 0; @@ -2787,7 +2779,7 @@ bool CWallet::CreateTransactionInternal( CScript scriptChange; // coin control: send change to custom address - if (!boost::get<CNoDestination>(&coin_control.destChange)) { + if (!std::get_if<CNoDestination>(&coin_control.destChange)) { scriptChange = GetScriptForDestination(coin_control.destChange); } else { // no coin control: send change to newly generated address // Note: We use a new key here to keep it from being obvious which side is the change. @@ -2819,7 +2811,7 @@ bool CWallet::CreateTransactionInternal( // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly // provided one if (coin_control.m_feerate && nFeeRateNeeded > *coin_control.m_feerate) { - error = strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(), nFeeRateNeeded.ToString()); + error = strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), nFeeRateNeeded.ToString(FeeEstimateMode::SAT_VB)); return false; } @@ -3049,7 +3041,7 @@ bool CWallet::CreateTransactionInternal( // to avoid conflicting with other possible uses of nSequence, // and in the spirit of "smallest possible change from prior // behavior." - const uint32_t nSequence = coin_control.m_signal_bip125_rbf.get_value_or(m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); + const uint32_t nSequence = coin_control.m_signal_bip125_rbf.value_or(m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); for (const auto& coin : selected_coins) { txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence)); } @@ -3086,14 +3078,15 @@ bool CWallet::CreateTransactionInternal( // Before we return success, we assume any change key will be used to prevent // accidental re-use. reservedest.KeepDestination(); + fee_calc_out = feeCalc; WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n", nFeeRet, nBytes, nFeeNeeded, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay, feeCalc.est.pass.start, feeCalc.est.pass.end, - 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool), + (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) > 0.0 ? 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) : 0.0, feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool, feeCalc.est.fail.start, feeCalc.est.fail.end, - 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool), + (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0, feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool); return true; } @@ -3105,19 +3098,21 @@ bool CWallet::CreateTransaction( int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, + FeeCalculation& fee_calc_out, bool sign) { int nChangePosIn = nChangePosInOut; - CTransactionRef tx2 = tx; - bool res = CreateTransactionInternal(vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, sign); + Assert(!tx); // tx is an out-param. TODO change the return type from bool to tx (or nullptr) + bool res = CreateTransactionInternal(vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, fee_calc_out, sign); // try with avoidpartialspends unless it's enabled already if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) { CCoinControl tmp_cc = coin_control; tmp_cc.m_avoid_partial_spends = true; CAmount nFeeRet2; + CTransactionRef tx2; int nChangePosInOut2 = nChangePosIn; bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results - if (CreateTransactionInternal(vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, sign)) { + if (CreateTransactionInternal(vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, fee_calc_out, sign)) { // if fee of this alternative one is within the range of the max fee, we use this one const bool use_aps = nFeeRet2 <= nFeeRet + m_max_aps_fee; WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n", nFeeRet, nFeeRet2, use_aps ? "grouped" : "non-grouped"); @@ -3176,10 +3171,10 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) LOCK(cs_wallet); fFirstRunRet = false; - DBErrors nLoadWalletRet = WalletBatch(*database,"cr+").LoadWallet(this); + DBErrors nLoadWalletRet = WalletBatch(GetDatabase()).LoadWallet(this); if (nLoadWalletRet == DBErrors::NEED_REWRITE) { - if (database->Rewrite("\x04pool")) + if (GetDatabase().Rewrite("\x04pool")) { for (const auto& spk_man_pair : m_spk_managers) { spk_man_pair.second->RewriteDB(); @@ -3203,7 +3198,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) { AssertLockHeld(cs_wallet); - DBErrors nZapSelectTxRet = WalletBatch(*database, "cr+").ZapSelectTx(vHashIn, vHashOut); + DBErrors nZapSelectTxRet = WalletBatch(GetDatabase()).ZapSelectTx(vHashIn, vHashOut); for (const uint256& hash : vHashOut) { const auto& it = mapWallet.find(hash); wtxOrdered.erase(it->second.m_it_wtxOrdered); @@ -3215,7 +3210,7 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256 if (nZapSelectTxRet == DBErrors::NEED_REWRITE) { - if (database->Rewrite("\x04pool")) + if (GetDatabase().Rewrite("\x04pool")) { for (const auto& spk_man_pair : m_spk_managers) { spk_man_pair.second->RewriteDB(); @@ -3253,14 +3248,14 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose) { - WalletBatch batch(*database); + WalletBatch batch(GetDatabase()); return SetAddressBookWithDB(batch, address, strName, strPurpose); } bool CWallet::DelAddressBook(const CTxDestination& address) { bool is_mine; - WalletBatch batch(*database); + WalletBatch batch(GetDatabase()); { LOCK(cs_wallet); // If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted) @@ -3719,7 +3714,7 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const bool CWallet::AddDestData(WalletBatch& batch, const CTxDestination &dest, const std::string &key, const std::string &value) { - if (boost::get<CNoDestination>(&dest)) + if (std::get_if<CNoDestination>(&dest)) return false; m_address_book[dest].destdata.insert(std::make_pair(key, value)); @@ -3775,7 +3770,7 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons // 2. Path to an existing directory. // 3. Path to a symlink to a directory. // 4. For backwards compatibility, the name of a data file in -walletdir. - const fs::path& wallet_path = fs::absolute(name, GetWalletDir()); + const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), name); fs::file_type path_type = fs::symlink_status(wallet_path).type(); if (!(path_type == fs::file_not_found || path_type == fs::directory_file || (path_type == fs::symlink_file && fs::is_directory(wallet_path)) || @@ -4007,7 +4002,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st int rescan_height = 0; if (!gArgs.GetBoolArg("-rescan", false)) { - WalletBatch batch(*walletInstance->database); + WalletBatch batch(walletInstance->GetDatabase()); CBlockLocator locator; if (batch.ReadBestBlock(locator)) { if (const Optional<int> fork_height = chain.findLocatorFork(locator)) { @@ -4050,16 +4045,13 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st // No need to read and scan block if block was created before // our wallet birthday (as adjusted for block time variability) - // The way the 'time_first_key' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0. - Optional<int64_t> time_first_key = MakeOptional(false, int64_t());; + Optional<int64_t> time_first_key; for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) { int64_t time = spk_man->GetTimeFirstKey(); if (!time_first_key || time < *time_first_key) time_first_key = time; } if (time_first_key) { - if (Optional<int> first_block = chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, nullptr)) { - rescan_height = *first_block; - } + chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, FoundBlock().height(rescan_height)); } { @@ -4070,7 +4062,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st } } walletInstance->chainStateFlushed(chain.getTipLocator()); - walletInstance->database->IncrementUpdateCounter(); + walletInstance->GetDatabase().IncrementUpdateCounter(); } { @@ -4101,36 +4093,33 @@ const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest return &address_book_it->second; } -bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings) +bool CWallet::UpgradeWallet(int version, bilingual_str& error) { int prev_version = GetVersion(); - int nMaxVersion = version; - if (nMaxVersion == 0) // the -upgradewallet without argument case - { + if (version == 0) { WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST); - nMaxVersion = FEATURE_LATEST; - SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately + version = FEATURE_LATEST; } else { - WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); + WalletLogPrintf("Allowing wallet upgrade up to %i\n", version); } - if (nMaxVersion < GetVersion()) - { - error = _("Cannot downgrade wallet"); + if (version < prev_version) { + error = strprintf(_("Cannot downgrade wallet from version %i to version %i. Wallet version unchanged."), prev_version, version); return false; } - SetMaxVersion(nMaxVersion); LOCK(cs_wallet); // Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT - int max_version = GetVersion(); - if (!CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) { - error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified."); + if (!CanSupportFeature(FEATURE_HD_SPLIT) && version >= FEATURE_HD_SPLIT && version < FEATURE_PRE_SPLIT_KEYPOOL) { + error = strprintf(_("Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified."), prev_version, version, FEATURE_PRE_SPLIT_KEYPOOL); return false; } + // Permanently upgrade to the version + SetMinVersion(GetClosestWalletFeature(version)); + for (auto spk_man : GetActiveScriptPubKeyMans()) { - if (!spk_man->Upgrade(prev_version, error)) { + if (!spk_man->Upgrade(prev_version, version, error)) { return false; } } @@ -4151,7 +4140,7 @@ void CWallet::postInitProcess() bool CWallet::BackupWallet(const std::string& strDest) const { - return database->Backup(strDest); + return GetDatabase().Backup(strDest); } CKeyPool::CKeyPool() @@ -4493,7 +4482,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans() void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal) { - WalletBatch batch(*database); + WalletBatch batch(GetDatabase()); if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) { throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed"); } @@ -4533,7 +4522,7 @@ DescriptorScriptPubKeyMan* CWallet::GetDescriptorScriptPubKeyMan(const WalletDes return nullptr; } -ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label) +ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal) { if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { WalletLogPrintf("Cannot add WalletDescriptor to a non-descriptor wallet\n"); @@ -4578,7 +4567,10 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat } // Top up key pool, the manager will generate new scriptPubKeys internally - new_spk_man->TopUp(); + if (!new_spk_man->TopUp()) { + WalletLogPrintf("Could not top up scriptPubKeys\n"); + return nullptr; + } // Apply the label if necessary // Note: we disable labels for ranged descriptors @@ -4590,7 +4582,7 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat } CTxDestination dest; - if (ExtractDestination(script_pub_keys.at(0), dest)) { + if (!internal && ExtractDestination(script_pub_keys.at(0), dest)) { SetAddressBook(dest, label, "receive"); } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 21cc888712..4fc4466604 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -55,7 +55,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet, Optional<bool> load_on std::vector<std::shared_ptr<CWallet>> GetWallets(); std::shared_ptr<CWallet> GetWallet(const std::string& name); std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings); -std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings); +std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, Optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings); std::unique_ptr<interfaces::Handler> HandleLoadWallet(LoadWalletFn load_wallet); std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); @@ -644,9 +644,6 @@ private: //! the current wallet version: clients below this version are not able to load the wallet int nWalletVersion GUARDED_BY(cs_wallet){FEATURE_BASE}; - //! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded - int nWalletMaxVersion GUARDED_BY(cs_wallet) = FEATURE_BASE; - int64_t nNextResend = 0; bool fBroadcastTransactions = false; // Local time that the tip block was received. Used to schedule wallet rebroadcasts. @@ -706,7 +703,7 @@ private: std::string m_name; /** Internal database handle. */ - std::unique_ptr<WalletDatabase> database; + std::unique_ptr<WalletDatabase> const m_database; /** * The following is used to keep track of how far behind the wallet is @@ -731,7 +728,7 @@ private: // ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure std::map<uint256, std::unique_ptr<ScriptPubKeyMan>> m_spk_managers; - bool CreateTransactionInternal(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, bool sign); + bool CreateTransactionInternal(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, bool sign); public: /* @@ -740,14 +737,11 @@ public: */ mutable RecursiveMutex cs_wallet; - /** Get database handle used by this wallet. Ideally this function would - * not be necessary. - */ - WalletDatabase& GetDBHandle() + WalletDatabase& GetDatabase() const override { - return *database; + assert(static_cast<bool>(m_database)); + return *m_database; } - WalletDatabase& GetDatabase() override { return *database; } /** * Select a set of coins such that nValueRet >= nTargetValue and at least @@ -769,7 +763,7 @@ public: CWallet(interfaces::Chain* chain, const std::string& name, std::unique_ptr<WalletDatabase> database) : m_chain(chain), m_name(name), - database(std::move(database)) + m_database(std::move(database)) { } @@ -808,8 +802,8 @@ public: const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! check whether we are allowed to upgrade (or already support) to the named feature - bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } + //! check whether we support the named feature + bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return IsFeatureSupported(nWalletVersion, wf); } /** * populate vCoins with vector of available COutputs. @@ -861,7 +855,7 @@ public: //! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } + bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; return true; } /** * Adds a destination data tuple to the store, and saves it to disk @@ -944,7 +938,7 @@ public: Balance GetBalance(int min_depth = 0, bool avoid_reuse = true) const; CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const; - OutputType TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend); + OutputType TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const; /** * Insert additional inputs into the transaction by @@ -982,7 +976,7 @@ public: * selected by SelectCoins(); Also create the change output, when needed * @note passing nChangePosInOut as -1 will result in setting a random position */ - bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, bool sign = true); + bool CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, bool sign = true); /** * Submit the transaction to the node's mempool and then relay to peers. * Should be called after CreateTransaction unless you want to abort @@ -1084,11 +1078,8 @@ public: unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower - void SetMinVersion(enum WalletFeature, WalletBatch* batch_in = nullptr, bool fExplicit = false) override; - - //! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format) - bool SetMaxVersion(int nVersion); + //! signify that a particular wallet feature is now used. + void SetMinVersion(enum WalletFeature, WalletBatch* batch_in = nullptr) override; //! get the current wallet format (the oldest client version guaranteed to understand this wallet) int GetVersion() const { LOCK(cs_wallet); return nWalletVersion; } @@ -1209,7 +1200,7 @@ public: }; /** Upgrade the wallet */ - bool UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings); + bool UpgradeWallet(int version, bilingual_str& error); //! Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers std::set<ScriptPubKeyMan*> GetActiveScriptPubKeyMans() const; @@ -1288,7 +1279,7 @@ public: DescriptorScriptPubKeyMan* GetDescriptorScriptPubKeyMan(const WalletDescriptor& desc) const; //! Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type - ScriptPubKeyMan* AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label); + ScriptPubKeyMan* AddWalletDescriptor(WalletDescriptor& desc, const FlatSigningProvider& signing_provider, const std::string& label, bool internal); }; /** diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 5bf21eb91f..4e6270220e 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -14,7 +14,12 @@ #include <util/system.h> #include <util/time.h> #include <util/translation.h> +#ifdef USE_BDB #include <wallet/bdb.h> +#endif +#ifdef USE_SQLITE +#include <wallet/sqlite.h> +#endif #include <wallet/wallet.h> #include <atomic> @@ -359,7 +364,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { ssValue >> hash; } - catch (...) {} + catch (const std::ios_base::failure&) {} bool fSkipCheck = false; @@ -421,7 +426,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, uint256 checksum; ssValue >> checksum; if ((checksum_valid = Hash(vchPrivKey) != checksum)) { - strErr = "Error reading wallet database: Crypted key corrupt"; + strErr = "Error reading wallet database: Encrypted key corrupt"; return false; } } @@ -940,7 +945,7 @@ void MaybeCompactWalletDB() } for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) { - WalletDatabase& dbh = pwallet->GetDBHandle(); + WalletDatabase& dbh = pwallet->GetDatabase(); unsigned int nUpdateCounter = dbh.nUpdateCounter; @@ -1008,9 +1013,17 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas Optional<DatabaseFormat> format; if (exists) { - if (ExistsBerkeleyDatabase(path)) { + if (IsBDBFile(BDBDataFile(path))) { format = DatabaseFormat::BERKELEY; } + if (IsSQLiteFile(SQLiteDataFile(path))) { + if (format) { + error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string())); + status = DatabaseStatus::FAILED_BAD_FORMAT; + return nullptr; + } + format = DatabaseFormat::SQLITE; + } } else if (options.require_existing) { error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string())); status = DatabaseStatus::FAILED_NOT_FOUND; @@ -1029,7 +1042,41 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas return nullptr; } + // A db already exists so format is set, but options also specifies the format, so make sure they agree + if (format && options.require_format && format != options.require_format) { + error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", path.string())); + status = DatabaseStatus::FAILED_BAD_FORMAT; + return nullptr; + } + + // Format is not set when a db doesn't already exist, so use the format specified by the options if it is set. + if (!format && options.require_format) format = options.require_format; + + // If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now. + if (!format) { +#ifdef USE_SQLITE + format = DatabaseFormat::SQLITE; +#endif +#ifdef USE_BDB + format = DatabaseFormat::BERKELEY; +#endif + } + + if (format == DatabaseFormat::SQLITE) { +#ifdef USE_SQLITE + return MakeSQLiteDatabase(path, options, status, error); +#endif + error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", path.string())); + status = DatabaseStatus::FAILED_BAD_FORMAT; + return nullptr; + } + +#ifdef USE_BDB return MakeBerkeleyDatabase(path, options, status, error); +#endif + error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", path.string())); + status = DatabaseStatus::FAILED_BAD_FORMAT; + return nullptr; } /** Return object for accessing dummy database with no read/write capabilities. */ @@ -1041,5 +1088,9 @@ std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase() /** Return object for accessing temporary in-memory database. */ std::unique_ptr<WalletDatabase> CreateMockWalletDatabase() { +#ifdef USE_BDB return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), ""); +#elif USE_SQLITE + return MakeUnique<SQLiteDatabase>("", "", true); +#endif } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index eda810ed8a..e7b2d7d780 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -8,7 +8,6 @@ #include <amount.h> #include <script/sign.h> -#include <wallet/bdb.h> #include <wallet/db.h> #include <wallet/walletutil.h> #include <key.h> @@ -204,8 +203,8 @@ private: } public: - explicit WalletBatch(WalletDatabase& database, const char* pszMode = "r+", bool _fFlushOnClose = true) : - m_batch(database.MakeBatch(pszMode, _fFlushOnClose)), + explicit WalletBatch(WalletDatabase &database, bool _fFlushOnClose = true) : + m_batch(database.MakeBatch(_fFlushOnClose)), m_database(database) { } diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index 4452840eb1..bc90491a2c 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -5,6 +5,7 @@ #include <fs.h> #include <util/system.h> #include <util/translation.h> +#include <wallet/dump.h> #include <wallet/salvage.h> #include <wallet/wallet.h> #include <wallet/walletutil.h> @@ -21,30 +22,27 @@ static void WalletToolReleaseWallet(CWallet* wallet) delete wallet; } -static void WalletCreate(CWallet* wallet_instance) +static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags) { LOCK(wallet_instance->cs_wallet); wallet_instance->SetMinVersion(FEATURE_HD_SPLIT); + wallet_instance->AddWalletFlags(wallet_creation_flags); - // generate a new HD seed - auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan(); - CPubKey seed = spk_man->GenerateNewSeed(); - spk_man->SetHDSeed(seed); + if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { + auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan(); + spk_man->SetupGeneration(false); + } else { + wallet_instance->SetupDescriptorScriptPubKeyMans(); + } tfm::format(std::cout, "Topping up keypool...\n"); wallet_instance->TopUpKeyPool(); } -static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, bool create) +static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options) { - DatabaseOptions options; DatabaseStatus status; - if (create) { - options.require_create = true; - } else { - options.require_existing = true; - } bilingual_str error; std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error); if (!database) { @@ -85,7 +83,7 @@ static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::pa } } - if (create) WalletCreate(wallet_instance.get()); + if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags); return wallet_instance; } @@ -95,6 +93,9 @@ static void WalletShowInfo(CWallet* wallet_instance) LOCK(wallet_instance->cs_wallet); tfm::format(std::cout, "Wallet info\n===========\n"); + tfm::format(std::cout, "Name: %s\n", wallet_instance->GetName()); + tfm::format(std::cout, "Format: %s\n", wallet_instance->GetDatabase().Format()); + tfm::format(std::cout, "Descriptors: %s\n", wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) ? "yes" : "no"); tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no"); tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no"); tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize()); @@ -102,36 +103,85 @@ static void WalletShowInfo(CWallet* wallet_instance) tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size()); } -bool ExecuteWalletToolFunc(const std::string& command, const std::string& name) +bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command, const std::string& name) { - fs::path path = fs::absolute(name, GetWalletDir()); + const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), name); + + if (args.IsArgSet("-format") && command != "createfromdump") { + tfm::format(std::cerr, "The -format option can only be used with the \"createfromdump\" command.\n"); + return false; + } + if (args.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") { + tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n"); + return false; + } + if (args.IsArgSet("-descriptors") && command != "create") { + tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n"); + return false; + } if (command == "create") { - std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ true); + DatabaseOptions options; + options.require_create = true; + if (args.GetBoolArg("-descriptors", false)) { + options.create_flags |= WALLET_FLAG_DESCRIPTORS; + options.require_format = DatabaseFormat::SQLITE; + } + + std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options); if (wallet_instance) { WalletShowInfo(wallet_instance.get()); wallet_instance->Close(); } - } else if (command == "info" || command == "salvage") { - if (command == "info") { - std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ false); - if (!wallet_instance) return false; - WalletShowInfo(wallet_instance.get()); - wallet_instance->Close(); - } else if (command == "salvage") { - bilingual_str error; - std::vector<bilingual_str> warnings; - bool ret = RecoverDatabaseFile(path, error, warnings); - if (!ret) { - for (const auto& warning : warnings) { - tfm::format(std::cerr, "%s\n", warning.original); - } - if (!error.empty()) { - tfm::format(std::cerr, "%s\n", error.original); - } + } else if (command == "info") { + DatabaseOptions options; + options.require_existing = true; + std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options); + if (!wallet_instance) return false; + WalletShowInfo(wallet_instance.get()); + wallet_instance->Close(); + } else if (command == "salvage") { +#ifdef USE_BDB + bilingual_str error; + std::vector<bilingual_str> warnings; + bool ret = RecoverDatabaseFile(path, error, warnings); + if (!ret) { + for (const auto& warning : warnings) { + tfm::format(std::cerr, "%s\n", warning.original); } + if (!error.empty()) { + tfm::format(std::cerr, "%s\n", error.original); + } + } + return ret; +#else + tfm::format(std::cerr, "Salvage command is not available as BDB support is not compiled"); + return false; +#endif + } else if (command == "dump") { + DatabaseOptions options; + options.require_existing = true; + std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options); + if (!wallet_instance) return false; + bilingual_str error; + bool ret = DumpWallet(*wallet_instance, error); + if (!ret && !error.empty()) { + tfm::format(std::cerr, "%s\n", error.original); return ret; } + tfm::format(std::cout, "The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n"); + return ret; + } else if (command == "createfromdump") { + bilingual_str error; + std::vector<bilingual_str> warnings; + bool ret = CreateFromDump(name, path, error, warnings); + for (const auto& warning : warnings) { + tfm::format(std::cout, "%s\n", warning.original); + } + if (!ret && !error.empty()) { + tfm::format(std::cerr, "%s\n", error.original); + } + return ret; } else { tfm::format(std::cerr, "Invalid command: %s\n", command); return false; diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h index d0b8d6812a..f544a6f727 100644 --- a/src/wallet/wallettool.h +++ b/src/wallet/wallettool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -10,7 +10,7 @@ namespace WalletTool { void WalletShowInfo(CWallet* wallet_instance); -bool ExecuteWalletToolFunc(const std::string& command, const std::string& file); +bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command, const std::string& file); } // namespace WalletTool diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index e4c72aed98..dd2f071b6c 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -29,65 +29,16 @@ fs::path GetWalletDir() return path; } -bool IsBerkeleyBtree(const fs::path& path) +bool IsFeatureSupported(int wallet_version, int feature_version) { - if (!fs::exists(path)) return false; - - // A Berkeley DB Btree file has at least 4K. - // This check also prevents opening lock files. - boost::system::error_code ec; - auto size = fs::file_size(path, ec); - if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string()); - if (size < 4096) return false; - - fsbridge::ifstream file(path, std::ios::binary); - if (!file.is_open()) return false; - - file.seekg(12, std::ios::beg); // Magic bytes start at offset 12 - uint32_t data = 0; - file.read((char*) &data, sizeof(data)); // Read 4 bytes of file to compare against magic - - // Berkeley DB Btree magic bytes, from: - // https://github.com/file/file/blob/5824af38469ec1ca9ac3ffd251e7afe9dc11e227/magic/Magdir/database#L74-L75 - // - big endian systems - 00 05 31 62 - // - little endian systems - 62 31 05 00 - return data == 0x00053162 || data == 0x62310500; + return wallet_version >= feature_version; } -std::vector<fs::path> ListWalletDir() +WalletFeature GetClosestWalletFeature(int version) { - const fs::path wallet_dir = GetWalletDir(); - const size_t offset = wallet_dir.string().size() + 1; - std::vector<fs::path> paths; - boost::system::error_code ec; - - for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) { - if (ec) { - LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string()); - continue; - } - - // Get wallet path relative to walletdir by removing walletdir from the wallet path. - // This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60. - const fs::path path = it->path().string().substr(offset); - - if (it->status().type() == fs::directory_file && IsBerkeleyBtree(it->path() / "wallet.dat")) { - // Found a directory which contains wallet.dat btree file, add it as a wallet. - paths.emplace_back(path); - } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBerkeleyBtree(it->path())) { - if (it->path().filename() == "wallet.dat") { - // Found top-level wallet.dat btree file, add top level directory "" - // as a wallet. - paths.emplace_back(); - } else { - // Found top-level btree file not called wallet.dat. Current bitcoin - // software will never create these files but will allow them to be - // opened in a shared database environment for backwards compatibility. - // Add it to the list of available wallets. - paths.emplace_back(path); - } - } + static constexpr std::array wallet_features{FEATURE_LATEST, FEATURE_PRE_SPLIT_KEYPOOL, FEATURE_NO_DEFAULT_KEY, FEATURE_HD_SPLIT, FEATURE_HD, FEATURE_COMPRPUBKEY, FEATURE_WALLETCRYPT, FEATURE_BASE}; + for (const WalletFeature& wf : wallet_features) { + if (version >= wf) return wf; } - - return paths; + return static_cast<WalletFeature>(0); } diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index afdcb2e18a..67b2ee2b98 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -29,7 +29,8 @@ enum WalletFeature FEATURE_LATEST = FEATURE_PRE_SPLIT_KEYPOOL }; - +bool IsFeatureSupported(int wallet_version, int feature_version); +WalletFeature GetClosestWalletFeature(int version); enum WalletFlags : uint64_t { // wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown @@ -64,9 +65,6 @@ enum WalletFlags : uint64_t { //! Get the path of the wallet directory. fs::path GetWalletDir(); -//! Get wallets in wallet directory. -std::vector<fs::path> ListWalletDir(); - /** Descriptor with some wallet metadata */ class WalletDescriptor { diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h index a55e02f2dc..660b0eed5d 100644 --- a/src/walletinitinterface.h +++ b/src/walletinitinterface.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/warnings.cpp b/src/warnings.cpp index 501bf7e637..60388cc713 100644 --- a/src/warnings.cpp +++ b/src/warnings.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,7 +14,6 @@ static Mutex g_warnings_mutex; static bilingual_str g_misc_warnings GUARDED_BY(g_warnings_mutex); -static bool fLargeWorkForkFound GUARDED_BY(g_warnings_mutex) = false; static bool fLargeWorkInvalidChainFound GUARDED_BY(g_warnings_mutex) = false; void SetMiscWarning(const bilingual_str& warning) @@ -23,18 +22,6 @@ void SetMiscWarning(const bilingual_str& warning) g_misc_warnings = warning; } -void SetfLargeWorkForkFound(bool flag) -{ - LOCK(g_warnings_mutex); - fLargeWorkForkFound = flag; -} - -bool GetfLargeWorkForkFound() -{ - LOCK(g_warnings_mutex); - return fLargeWorkForkFound; -} - void SetfLargeWorkInvalidChainFound(bool flag) { LOCK(g_warnings_mutex); @@ -60,10 +47,7 @@ bilingual_str GetWarnings(bool verbose) warnings_verbose.emplace_back(warnings_concise); } - if (fLargeWorkForkFound) { - warnings_concise = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); - warnings_verbose.emplace_back(warnings_concise); - } else if (fLargeWorkInvalidChainFound) { + if (fLargeWorkInvalidChainFound) { warnings_concise = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); warnings_verbose.emplace_back(warnings_concise); } diff --git a/src/warnings.h b/src/warnings.h index 28546eb753..c38edb4570 100644 --- a/src/warnings.h +++ b/src/warnings.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,8 +11,6 @@ struct bilingual_str; void SetMiscWarning(const bilingual_str& warning); -void SetfLargeWorkForkFound(bool flag); -bool GetfLargeWorkForkFound(); void SetfLargeWorkInvalidChainFound(bool flag); /** Format a string that describes several potential problems detected by the core. * @param[in] verbose bool diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp index 3938f6fd2c..90aefb0018 100644 --- a/src/zmq/zmqabstractnotifier.cpp +++ b/src/zmq/zmqabstractnotifier.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h index dddba8d6b6..6f0b202a18 100644 --- a/src/zmq/zmqabstractnotifier.h +++ b/src/zmq/zmqabstractnotifier.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2018 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index a7e9a34269..86f47d71f3 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -42,10 +42,8 @@ CZMQNotificationInterface* CZMQNotificationInterface::Create() for (const auto& entry : factories) { std::string arg("-zmq" + entry.first); - if (gArgs.IsArgSet(arg)) - { - const auto& factory = entry.second; - const std::string address = gArgs.GetArg(arg, ""); + const auto& factory = entry.second; + for (const std::string& address : gArgs.GetArgs(arg)) { std::unique_ptr<CZMQAbstractNotifier> notifier = factory(); notifier->SetType(entry.first); notifier->SetAddress(address); diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h index 788a383517..8f81bfd63f 100644 --- a/src/zmq/zmqnotificationinterface.h +++ b/src/zmq/zmqnotificationinterface.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index a0e7a0a600..168ba841c8 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -17,6 +17,7 @@ #include <cstdarg> #include <cstddef> #include <map> +#include <optional> #include <string> #include <utility> @@ -180,7 +181,7 @@ bool CZMQAbstractPublishNotifier::SendZmqMessage(const char *command, const void bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s to %s\n", hash.GetHex(), this->address); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -190,7 +191,7 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s to %s\n", hash.GetHex(), this->address); char data[32]; for (unsigned int i = 0; i < 32; i++) data[31 - i] = hash.begin()[i]; @@ -199,7 +200,7 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { - LogPrint(BCLog::ZMQ, "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish rawblock %s to %s\n", pindex->GetBlockHash().GetHex(), this->address); const Consensus::Params& consensusParams = Params().GetConsensus(); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); @@ -221,56 +222,49 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s\n", hash.GetHex()); + LogPrint(BCLog::ZMQ, "zmq: Publish rawtx %s to %s\n", hash.GetHex(), this->address); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); ss << transaction; return SendZmqMessage(MSG_RAWTX, &(*ss.begin()), ss.size()); } +// Helper function to send a 'sequence' topic message with the following structure: +// <32-byte hash> | <1-byte label> | <8-byte LE sequence> (optional) +static bool SendSequenceMsg(CZMQAbstractPublishNotifier& notifier, uint256 hash, char label, std::optional<uint64_t> sequence = {}) +{ + unsigned char data[sizeof(hash) + sizeof(label) + sizeof(uint64_t)]; + for (unsigned int i = 0; i < sizeof(hash); ++i) { + data[sizeof(hash) - 1 - i] = hash.begin()[i]; + } + data[sizeof(hash)] = label; + if (sequence) WriteLE64(data + sizeof(hash) + sizeof(label), *sequence); + return notifier.SendZmqMessage(MSG_SEQUENCE, data, sequence ? sizeof(data) : sizeof(hash) + sizeof(label)); +} -// TODO: Dedup this code to take label char, log string bool CZMQPublishSequenceNotifier::NotifyBlockConnect(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish sequence block connect %s\n", hash.GetHex()); - char data[sizeof(uint256)+1]; - for (unsigned int i = 0; i < sizeof(uint256); i++) - data[sizeof(uint256) - 1 - i] = hash.begin()[i]; - data[sizeof(data) - 1] = 'C'; // Block (C)onnect - return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data)); + LogPrint(BCLog::ZMQ, "zmq: Publish sequence block connect %s to %s\n", hash.GetHex(), this->address); + return SendSequenceMsg(*this, hash, /* Block (C)onnect */ 'C'); } bool CZMQPublishSequenceNotifier::NotifyBlockDisconnect(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish sequence block disconnect %s\n", hash.GetHex()); - char data[sizeof(uint256)+1]; - for (unsigned int i = 0; i < sizeof(uint256); i++) - data[sizeof(uint256) - 1 - i] = hash.begin()[i]; - data[sizeof(data) - 1] = 'D'; // Block (D)isconnect - return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data)); + LogPrint(BCLog::ZMQ, "zmq: Publish sequence block disconnect %s to %s\n", hash.GetHex(), this->address); + return SendSequenceMsg(*this, hash, /* Block (D)isconnect */ 'D'); } bool CZMQPublishSequenceNotifier::NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool acceptance %s\n", hash.GetHex()); - unsigned char data[sizeof(uint256)+sizeof(mempool_sequence)+1]; - for (unsigned int i = 0; i < sizeof(uint256); i++) - data[sizeof(uint256) - 1 - i] = hash.begin()[i]; - data[sizeof(uint256)] = 'A'; // Mempool (A)cceptance - WriteLE64(data+sizeof(uint256)+1, mempool_sequence); - return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data)); + LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool acceptance %s to %s\n", hash.GetHex(), this->address); + return SendSequenceMsg(*this, hash, /* Mempool (A)cceptance */ 'A', mempool_sequence); } bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence) { uint256 hash = transaction.GetHash(); - LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool removal %s\n", hash.GetHex()); - unsigned char data[sizeof(uint256)+sizeof(mempool_sequence)+1]; - for (unsigned int i = 0; i < sizeof(uint256); i++) - data[sizeof(uint256) - 1 - i] = hash.begin()[i]; - data[sizeof(uint256)] = 'R'; // Mempool (R)emoval - WriteLE64(data+sizeof(uint256)+1, mempool_sequence); - return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data)); + LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool removal %s to %s\n", hash.GetHex(), this->address); + return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence); } diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h index f13ed6f537..c1d66bddb1 100644 --- a/src/zmq/zmqpublishnotifier.h +++ b/src/zmq/zmqpublishnotifier.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2018 The Bitcoin Core developers +// Copyright (c) 2015-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp index 1dd751b493..81859f924f 100644 --- a/src/zmq/zmqrpc.cpp +++ b/src/zmq/zmqrpc.cpp @@ -52,9 +52,9 @@ static RPCHelpMan getzmqnotifications() } const CRPCCommand commands[] = -{ // category name actor (function) argNames - // ----------------- ------------------------ ----------------------- ---------- - { "zmq", "getzmqnotifications", &getzmqnotifications, {} }, +{ // category actor (function) + // ----------------- ----------------------- + { "zmq", &getzmqnotifications, }, }; } // anonymous namespace |