From 9ef38758a69abfb6166099bf8dea1d69e258ae00 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 21 Oct 2016 12:15:19 -0400 Subject: [PATCH 01/91] Add missing cs_main lock to ::GETBLOCKTXN processing Note that this is not a major issue as, in order for the missing lock to cause issues, you have to receive a GETBLOCKTXN message while reindexing, adding a block header via RPC, etc, which results in either a table rehash or an insert into the bucket which you are currently looking at. Github-Pull: #8995 Rebased-From: dfe79060a62c8de098e75d527d97b99c3b10de50 --- src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 61d0aaf0b..84f4607db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5388,6 +5388,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, BlockTransactionsRequest req; vRecv >> req; + LOCK(cs_main); + BlockMap::iterator it = mapBlockIndex.find(req.blockhash); if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) { LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->id); From ce0d817b9b59baa243c3ac0844a654704872aa2f Mon Sep 17 00:00:00 2001 From: maiiz Date: Mon, 18 Jul 2016 15:01:34 +0800 Subject: [PATCH 02/91] Fix relaypriority calculation error Github-Pull: #8357 Rebased-From: 94a34a5d951cee59ef9c9274c5ad49ac2a91ab8a --- src/coins.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coins.cpp b/src/coins.cpp index 39db7dedf..8ff652b47 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -275,7 +275,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount assert(coins); if (!coins->IsAvailable(txin.prevout.n)) continue; if (coins->nHeight <= nHeight) { - dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight); + dResult += (double)(coins->vout[txin.prevout.n].nValue) * (nHeight-coins->nHeight); inChainInputValue += coins->vout[txin.prevout.n].nValue; } } From 1d048b917b83489f9e56d8fab522475544b98793 Mon Sep 17 00:00:00 2001 From: jnewbery Date: Mon, 26 Sep 2016 17:01:10 -0400 Subject: [PATCH 03/91] Don't return the address of a P2SH of a P2SH. Github-Pull: #8845 Rebased-From: d51f18246165b580761af824f1bb4a49b6908f28 --- src/rpc/rawtransaction.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 3270cd384..b2bbb8b3e 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -535,7 +535,7 @@ UniValue decodescript(const UniValue& params, bool fHelp) " \"address\" (string) bitcoin address\n" " ,...\n" " ],\n" - " \"p2sh\",\"address\" (string) script address\n" + " \"p2sh\",\"address\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n" "}\n" "\nExamples:\n" + HelpExampleCli("decodescript", "\"hexstring\"") @@ -554,7 +554,15 @@ UniValue decodescript(const UniValue& params, bool fHelp) } ScriptPubKeyToJSON(script, r, false); - r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString())); + UniValue type; + type = find_value(r, "type"); + + if (type.isStr() && type.get_str() != "scripthash") { + // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH, + // don't return the address for a P2SH of the P2SH. + r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString())); + } + return r; } From 6d05fe115b07588f41631663ace2f3f14c3ed3d7 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 21 Sep 2016 22:31:23 +0000 Subject: [PATCH 04/91] Add MIT license to Makefiles Github-Pull: #8784 Rebased-From: f4dffdd6bffc58377b7505b639f0431244321c32 --- Makefile.am | 4 ++++ src/Makefile.am | 4 ++++ src/Makefile.bench.include | 4 ++++ src/Makefile.leveldb.include | 4 ++++ src/Makefile.qt.include | 4 ++++ src/Makefile.qttest.include | 4 ++++ src/Makefile.test.include | 4 ++++ 7 files changed, 28 insertions(+) diff --git a/Makefile.am b/Makefile.am index b10d08506..f3dc016b9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,7 @@ +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + ACLOCAL_AMFLAGS = -I build-aux/m4 SUBDIRS = src .PHONY: deploy FORCE diff --git a/src/Makefile.am b/src/Makefile.am index e3eaacdb4..1e033de9d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,7 @@ +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + DIST_SUBDIRS = secp256k1 univalue AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 4067ceb39..8c024a8c4 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -1,3 +1,7 @@ +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + bin_PROGRAMS += bench/bench_bitcoin BENCH_SRCDIR = bench BENCH_BINARY = bench/bench_bitcoin$(EXEEXT) diff --git a/src/Makefile.leveldb.include b/src/Makefile.leveldb.include index 4b3cd6364..d7346aa18 100644 --- a/src/Makefile.leveldb.include +++ b/src/Makefile.leveldb.include @@ -1,3 +1,7 @@ +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + LIBLEVELDB_INT = leveldb/libleveldb.a LIBMEMENV_INT = leveldb/libmemenv.a diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index bbef64176..8e6805d4a 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -1,3 +1,7 @@ +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + bin_PROGRAMS += qt/bitcoin-qt EXTRA_LIBRARIES += qt/libbitcoinqt.a diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 813a343ff..a071fe136 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -1,3 +1,7 @@ +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + bin_PROGRAMS += qt/test/test_bitcoin-qt TESTS += qt/test/test_bitcoin-qt diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 27e769474..ef30eeb4a 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,3 +1,7 @@ +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + TESTS += test/test_bitcoin bin_PROGRAMS += test/test_bitcoin TEST_SRCDIR = test From fa58e55cef9a901b433544338dccd562dbe461ee Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 21 Sep 2016 22:35:21 +0000 Subject: [PATCH 05/91] Add MIT license to autogen.sh and share/genbuild.sh Github-Pull: #8784 Rebased-From: 3b4b6dcdd77f3ba76fb0cda6f2c277ec1629d8d3 --- autogen.sh | 4 ++++ share/genbuild.sh | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/autogen.sh b/autogen.sh index 46e36ff5b..27417daf7 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + set -e srcdir="$(dirname $0)" cd "$srcdir" diff --git a/share/genbuild.sh b/share/genbuild.sh index 1ef77d706..eecac4bd0 100755 --- a/share/genbuild.sh +++ b/share/genbuild.sh @@ -1,4 +1,8 @@ #!/bin/sh +# Copyright (c) 2012-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + if [ $# -gt 1 ]; then cd "$2" fi From 2cfcca7ca6f4036845f8e845cb4b55bd4e07ed64 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 21 Sep 2016 22:54:49 +0000 Subject: [PATCH 06/91] Trivial: build-aux/m4/l_atomic: Fix typo Github-Pull: #8784 Rebased-From: 3f8a5d8f6e95c3c1aa62433abc5edb0c93caae11 --- build-aux/m4/l_atomic.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4 index 906724b64..1cb13587a 100644 --- a/build-aux/m4/l_atomic.m4 +++ b/build-aux/m4/l_atomic.m4 @@ -32,7 +32,7 @@ AC_DEFUN([CHECK_ATOMIC], [ AC_MSG_RESULT([yes]) ],[ AC_MSG_RESULT([no]) - AC_MSG_FAILURE([cannot figure our how to use std::atomic]) + AC_MSG_FAILURE([cannot figure out how to use std::atomic]) ]) ]) From b16cdb71ff20ebf23372d116e9bb4bbe84d30fce Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 21 Sep 2016 22:54:41 +0000 Subject: [PATCH 07/91] Add MIT license to build-aux/m4 scripts Github-Pull: #8784 Rebased-From: 0c4e6ce88f58c13ed81807e3a5bef28b673aa503 --- build-aux/m4/bitcoin_find_bdb48.m4 | 4 ++++ build-aux/m4/bitcoin_qt.m4 | 4 ++++ build-aux/m4/bitcoin_subdir_to_include.m4 | 4 ++++ build-aux/m4/l_atomic.m4 | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/build-aux/m4/bitcoin_find_bdb48.m4 b/build-aux/m4/bitcoin_find_bdb48.m4 index 2aa493a6a..0c3d49c2b 100644 --- a/build-aux/m4/bitcoin_find_bdb48.m4 +++ b/build-aux/m4/bitcoin_find_bdb48.m4 @@ -1,3 +1,7 @@ +dnl Copyright (c) 2013-2015 The Bitcoin Core developers +dnl Distributed under the MIT software license, see the accompanying +dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. + AC_DEFUN([BITCOIN_FIND_BDB48],[ AC_MSG_CHECKING([for Berkeley DB C++ headers]) BDB_CPPFLAGS= diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index d26136cbe..509283a0b 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -1,3 +1,7 @@ +dnl Copyright (c) 2013-2016 The Bitcoin Core developers +dnl Distributed under the MIT software license, see the accompanying +dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. + dnl Helper for cases where a qt dependency is not met. dnl Output: If qt version is auto, set bitcoin_enable_qt to false. Else, exit. AC_DEFUN([BITCOIN_QT_FAIL],[ diff --git a/build-aux/m4/bitcoin_subdir_to_include.m4 b/build-aux/m4/bitcoin_subdir_to_include.m4 index 66f106c7d..7841042ac 100644 --- a/build-aux/m4/bitcoin_subdir_to_include.m4 +++ b/build-aux/m4/bitcoin_subdir_to_include.m4 @@ -1,3 +1,7 @@ +dnl Copyright (c) 2013-2014 The Bitcoin Core developers +dnl Distributed under the MIT software license, see the accompanying +dnl file COPYING or http://www.opensource.org/licenses/mit-license.php. + dnl BITCOIN_SUBDIR_TO_INCLUDE([CPPFLAGS-VARIABLE-NAME],[SUBDIRECTORY-NAME],[HEADER-FILE]) dnl SUBDIRECTORY-NAME must end with a path separator AC_DEFUN([BITCOIN_SUBDIR_TO_INCLUDE],[ diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4 index 1cb13587a..75c43f9a9 100644 --- a/build-aux/m4/l_atomic.m4 +++ b/build-aux/m4/l_atomic.m4 @@ -1,3 +1,9 @@ +dnl Copyright (c) 2015 Tim Kosse +dnl Copying and distribution of this file, with or without modification, are +dnl permitted in any medium without royalty provided the copyright notice +dnl and this notice are preserved. This file is offered as-is, without any +dnl warranty. + # Some versions of gcc/libstdc++ require linking with -latomic if # using the C++ atomic library. # From 2e2388a5cbb9a6e101b36e4501698fec538a5738 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 27 Oct 2016 14:53:30 +0200 Subject: [PATCH 08/91] Move release notes to release-notes/release-notes-0.13.1.md And clean out current release notes, ready for next release from this branch. --- doc/release-notes.md | 363 +------------------ doc/release-notes/release-notes-0.13.1.md | 410 ++++++++++++++++++++++ 2 files changed, 419 insertions(+), 354 deletions(-) create mode 100644 doc/release-notes/release-notes-0.13.1.md diff --git a/doc/release-notes.md b/doc/release-notes.md index 75c2d61be..e54f9ac02 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,10 +1,9 @@ -Bitcoin Core version 0.13.1 is now available from: +Bitcoin Core version 0.13.x is now available from: - + -This is a new minor version release, including activation parameters for the -segwit softfork, various bugfixes and performance improvements, as well as -updated translations. +This is a new minor version release, including ..., various bugfixes and +performance improvements, as well as updated translations. Please report bugs using the issue tracker at github: @@ -43,197 +42,10 @@ but severe issues with the libc++ version on 10.7.x keep it from running reliabl Notable changes =============== -Segregated witness soft fork ----------------------------- +Example item +--------------- -Segregated witness (segwit) is a soft fork that, if activated, will -allow transaction-producing software to separate (segregate) transaction -signatures (witnesses) from the part of the data in a transaction that is -covered by the txid. This provides several immediate benefits: - -- **Elimination of unwanted transaction malleability:** Segregating the witness - allows both existing and upgraded software to calculate the transaction - identifier (txid) of transactions without referencing the witness, which can - sometimes be changed by third-parties (such as miners) or by co-signers in a - multisig spend. This solves all known cases of unwanted transaction - malleability, which is a problem that makes programming Bitcoin wallet - software more difficult and which seriously complicates the design of smart - contracts for Bitcoin. - -- **Capacity increase:** Segwit transactions contain new fields that are not - part of the data currently used to calculate the size of a block, which - allows a block containing segwit transactions to hold more data than allowed - by the current maximum block size. Estimates based on the transactions - currently found in blocks indicate that if all wallets switch to using - segwit, the network will be able to support about 70% more transactions. The - network will also be able to support more of the advanced-style payments - (such as multisig) than it can support now because of the different weighting - given to different parts of a transaction after segwit activates (see the - following section for details). - -- **Weighting data based on how it affects node performance:** Some parts of - each Bitcoin block need to be stored by nodes in order to validate future - blocks; other parts of a block can be immediately forgotten (pruned) or used - only for helping other nodes sync their copy of the block chain. One large - part of the immediately prunable data are transaction signatures (witnesses), - and segwit makes it possible to give a different "weight" to segregated - witnesses to correspond with the lower demands they place on node resources. - Specifically, each byte of a segregated witness is given a weight of 1, each - other byte in a block is given a weight of 4, and the maximum allowed weight - of a block is 4 million. Weighting the data this way better aligns the most - profitable strategy for creating blocks with the long-term costs of block - validation. - -- **Signature covers value:** A simple improvement in the way signatures are - generated in segwit simplifies the design of secure signature generators - (such as hardware wallets), reduces the amount of data the signature - generator needs to download, and allows the signature generator to operate - more quickly. This is made possible by having the generator sign the amount - of bitcoins they think they are spending, and by having full nodes refuse to - accept those signatures unless the amount of bitcoins being spent is exactly - the same as was signed. For non-segwit transactions, wallets instead had to - download the complete previous transactions being spent for every payment - they made, which could be a slow operation on hardware wallets and in other - situations where bandwidth or computation speed was constrained. - -- **Linear scaling of sighash operations:** In 2015 a block was produced that - required about 25 seconds to validate on modern hardware because of the way - transaction signature hashes are performed. Other similar blocks, or blocks - that could take even longer to validate, can still be produced today. The - problem that caused this can't be fixed in a soft fork without unwanted - side-effects, but transactions that opt-in to using segwit will now use a - different signature method that doesn't suffer from this problem and doesn't - have any unwanted side-effects. - -- **Increased security for multisig:** Bitcoin addresses (both P2PKH addresses - that start with a '1' and P2SH addresses that start with a '3') use a hash - function known as RIPEMD-160. For P2PKH addresses, this provides about 160 - bits of security---which is beyond what cryptographers believe can be broken - today. But because P2SH is more flexible, only about 80 bits of security is - provided per address. Although 80 bits is very strong security, it is within - the realm of possibility that it can be broken by a powerful adversary. - Segwit allows advanced transactions to use the SHA256 hash function instead, - which provides about 128 bits of security (that is 281 trillion times as - much security as 80 bits and is equivalent to the maximum bits of security - believed to be provided by Bitcoin's choice of parameters for its Elliptic - Curve Digital Security Algorithm [ECDSA].) - -- **More efficient almost-full-node security** Satoshi Nakamoto's original - Bitcoin paper describes a method for allowing newly-started full nodes to - skip downloading and validating some data from historic blocks that are - protected by large amounts of proof of work. Unfortunately, Nakamoto's - method can't guarantee that a newly-started node using this method will - produce an accurate copy of Bitcoin's current ledger (called the UTXO set), - making the node vulnerable to falling out of consensus with other nodes. - Although the problems with Nakamoto's method can't be fixed in a soft fork, - Segwit accomplishes something similar to his original proposal: it makes it - possible for a node to optionally skip downloading some blockchain data - (specifically, the segregated witnesses) while still ensuring that the node - can build an accurate copy of the UTXO set for the block chain with the most - proof of work. Segwit enables this capability at the consensus layer, but - note that Bitcoin Core does not provide an option to use this capability as - of this 0.13.1 release. - -- **Script versioning:** Segwit makes it easy for future soft forks to allow - Bitcoin users to individually opt-in to almost any change in the Bitcoin - Script language when those users receive new transactions. Features - currently being researched by Bitcoin Core contributors that may use this - capability include support for Schnorr signatures, which can improve the - privacy and efficiency of multisig transactions (or transactions with - multiple inputs), and Merklized Abstract Syntax Trees (MAST), which can - improve the privacy and efficiency of scripts with two or more conditions. - Other Bitcoin community members are studying several other improvements - that can be made using script versioning. - -Activation for the segwit soft fork is being managed using BIP9 -versionbits. Segwit's version bit is bit 1, and nodes will begin -tracking which blocks signal support for segwit at the beginning of the -first retarget period after segwit's start date of 15 November 2016. If -95% of blocks within a 2,016-block retarget period (about two weeks) -signal support for segwit, the soft fork will be locked in. After -another 2,016 blocks, segwit will activate. - -For more information about segwit, please see the [segwit FAQ][], the -[segwit wallet developers guide][] or BIPs [141][BIP141], [143][BIP143], -[144][BIP144], and [145][BIP145]. If you're a miner or mining pool -operator, please see the [versionbits FAQ][] for information about -signaling support for a soft fork. - -[Segwit FAQ]: https://bitcoincore.org/en/2016/01/26/segwit-benefits/ -[segwit wallet developers guide]: https://bitcoincore.org/en/segwit_wallet_dev/ -[BIP141]: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki -[BIP143]: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki -[BIP144]: https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki -[BIP145]: https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki -[versionbits FAQ]: https://bitcoincore.org/en/2016/06/08/version-bits-miners-faq/ - - -Null dummy soft fork -------------------- - -Combined with the segwit soft fork is an additional change that turns a -long-existing network relay policy into a consensus rule. The -`OP_CHECKMULTISIG` and `OP_CHECKMULTISIGVERIFY` opcodes consume an extra -stack element ("dummy element") after signature validation. The dummy -element is not inspected in any manner, and could be replaced by any -value without invalidating the script. - -Because any value can be used for this dummy element, it's possible for -a third-party to insert data into other people's transactions, changing -the transaction's txid (called transaction malleability) and possibly -causing other problems. - -Since Bitcoin Core 0.10.0, nodes have defaulted to only relaying and -mining transactions whose dummy element was a null value (0x00, also -called OP_0). The null dummy soft fork turns this relay rule into a -consensus rule both for non-segwit transactions and segwit transactions, -so that this method of mutating transactions is permanently eliminated -from the network. - -Signaling for the null dummy soft fork is done by signaling support -for segwit, and the null dummy soft fork will activate at the same time -as segwit. - -For more information, please see [BIP147][]. - -[BIP147]: https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki - -Low-level RPC changes ---------------------- - -- `importprunedfunds` only accepts two required arguments. Some versions accept - an optional third arg, which was always ignored. Make sure to never pass more - than two arguments. - - -Linux ARM builds ----------------- - -With the 0.13.0 release, pre-built Linux ARM binaries were added to the set of -uploaded executables. Additional detail on the ARM architecture targeted by each -is provided below. - -The following extra files can be found in the download directory or torrent: - -- `bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries targeting - the 32-bit ARMv7-A architecture. -- `bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries targeting - the 64-bit ARMv8-A architecture. - -ARM builds are still experimental. If you have problems on a certain device or -Linux distribution combination please report them on the bug tracker, it may be -possible to resolve them. Note that the device you use must be (backward) -compatible with the architecture targeted by the binary that you use. -For example, a Raspberry Pi 2 Model B or Raspberry Pi 3 Model B (in its 32-bit -execution state) device, can run the 32-bit ARMv7-A targeted binary. However, -no model of Raspberry Pi 1 device can run either binary because they are all -ARMv6 architecture devices that are not compatible with ARMv7-A or ARMv8-A. - -Note that Android is not considered ARM Linux in this context. The executables -are not expected to work out of the box on Android. - - -0.13.1 Change log +0.13.x Change log ================= Detailed release notes follow. This overview includes changes that affect @@ -241,170 +53,13 @@ behavior, not code moves, refactors and string updates. For convenience in locat the code changes and accompanying discussion, both the pull request and git merge commit are mentioned. -### Consensus -- #8636 `9dfa0c8` Implement NULLDUMMY softfork (BIP147) (jl2012) -- #8848 `7a34a46` Add NULLDUMMY verify flag in bitcoinconsensus.h (jl2012) -- #8937 `8b66659` Define start and end time for segwit deployment (sipa) - -### RPC and other APIs -- #8581 `526d2b0` Drop misleading option in importprunedfunds (MarcoFalke) -- #8699 `a5ec248` Remove createwitnessaddress RPC command (jl2012) -- #8780 `794b007` Deprecate getinfo (MarcoFalke) -- #8832 `83ad563` Throw JSONRPCError when utxo set can not be read (MarcoFalke) -- #8884 `b987348` getblockchaininfo help: pruneheight is the lowest, not highest, block (luke-jr) -- #8858 `3f508ed` rpc: Generate auth cookie in hex instead of base64 (laanwj) -- #8951 `7c2bf4b` RPC/Mining: getblocktemplate: Update and fix formatting of help (luke-jr) - -### Block and transaction handling -- #8611 `a9429ca` Reduce default number of blocks to check at startup (sipa) -- #8634 `3e80ab7` Add policy: null signature for failed CHECK(MULTI)SIG (jl2012) -- #8525 `1672225` Do not store witness txn in rejection cache (sipa) -- #8499 `9777fe1` Add several policy limits and disable uncompressed keys for segwit scripts (jl2012) -- #8526 `0027672` Make non-minimal OP_IF/NOTIF argument non-standard for P2WSH (jl2012) -- #8524 `b8c79a0` Precompute sighashes (sipa) -- #8651 `b8c79a0` Predeclare PrecomputedTransactionData as struct (sipa) - -### P2P protocol and network code -- #8740 `42ea51a` No longer send local address in addrMe (laanwj) -- #8427 `69d1cd2` Ignore `notfound` P2P messages (laanwj) -- #8573 `4f84082` Set jonasschnellis dns-seeder filter flag (jonasschnelli) -- #8712 `23feab1` Remove maxuploadtargets recommended minimum (jonasschnelli) -- #8862 `7ae6242` Fix a few cases where messages were sent after requested disconnect (theuni) -- #8393 `fe1975a` Support for compact blocks together with segwit (sipa) -- #8282 `2611ad7` Feeler connections to increase online addrs in the tried table (EthanHeilman) -- #8612 `2215c22` Check for compatibility with download in FindNextBlocksToDownload (sipa) -- #8606 `bbf379b` Fix some locks (sipa) -- #8594 `ab295bb` Do not add random inbound peers to addrman (gmaxwell) -- #8940 `5b4192b` Add x9 service bit support to dnsseed.bluematt.me, seed.bitcoinstats.com (TheBlueMatt, cdecker) -- #8944 `685e4c7` Remove bogus assert on number of oubound connections. (TheBlueMatt) -- #8949 `0dbc48a` Be more agressive in getting connections to peers with relevant services (gmaxwell) - -### Build system -- #8293 `fa5b249` Allow building libbitcoinconsensus without any univalue (luke-jr) -- #8492 `8b0bdd3` Allow building bench_bitcoin by itself (luke-jr) -- #8563 `147003c` Add configure check for -latomic (ajtowns) -- #8626 `ea51b0f` Berkeley DB v6 compatibility fix (netsafe) -- #8520 `75f2065` Remove check for `openssl/ec.h` (laanwj) - -### GUI -- #8481 `d9f0d4e` Fix minimize and close bugs (adlawren) -- #8487 `a37cec5` Persist the datadir after option reset (achow101) -- #8697 `41fd852` Fix op order to append first alert (rodasmith) -- #8678 `8e03382` Fix UI bug that could result in paying unexpected fee (jonasschnelli) -- #8911 `7634d8e` Translate all files, even if wallet disabled (laanwj) -- #8540 `1db3352` Fix random segfault when closing "Choose data directory" dialog (laanwj) -- #7579 `f1c0d78` Show network/chain errors in the GUI (jonasschnelli) - -### Wallet -- #8443 `464dedd` Trivial cleanup of HD wallet changes (jonasschnelli) -- #8539 `cb07f19` CDB: fix debug output (crowning-) -- #8664 `091cdeb` Fix segwit-related wallet bug (sdaftuar) -- #8693 `c6a6291` Add witness address to address book (instagibbs) -- #8765 `6288659` Remove "unused" ThreadFlushWalletDB from removeprunedfunds (jonasschnelli) - -### Tests and QA -- #8713 `ae8c7df` create_cache: Delete temp dir when done (MarcoFalke) -- #8716 `e34374e` Check legacy wallet as well (MarcoFalke) -- #8750 `d6ebe13` Refactor RPCTestHandler to prevent TimeoutExpired (MarcoFalke) -- #8652 `63462c2` remove root test directory for RPC tests (yurizhykin) -- #8724 `da94272` walletbackup: Sync blocks inside the loop (MarcoFalke) -- #8400 `bea02dc` enable rpcbind_test (yurizhykin) -- #8417 `f70be14` Add walletdump RPC test (including HD- & encryption-tests) (jonasschnelli) -- #8419 `a7aa3cc` Enable size accounting in mining unit tests (sdaftuar) -- #8442 `8bb1efd` Rework hd wallet dump test (MarcoFalke) -- #8528 `3606b6b` Update p2p-segwit.py to reflect correct behavior (instagibbs) -- #8531 `a27cdd8` abandonconflict: Use assert_equal (MarcoFalke) -- #8667 `6b07362` Fix SIGHASH_SINGLE bug in test_framework SignatureHash (jl2012) -- #8673 `03b0196` Fix obvious assignment/equality error in test (JeremyRubin) -- #8739 `cef633c` Fix broken sendcmpct test in p2p-compactblocks.py (sdaftuar) -- #8418 `ff893aa` Add tests for compact blocks (sdaftuar) -- #8803 `375437c` Ping regularly in p2p-segwit.py to keep connection alive (jl2012) -- #8827 `9bbe66e` Split up slow RPC calls to avoid pruning test timeouts (sdaftuar) -- #8829 `2a8bca4` Add bitcoin-tx JSON tests (jnewbery) -- #8834 `1dd1783` blockstore: Switch to dumb dbm (MarcoFalke) -- #8835 `d87227d` nulldummy.py: Don't run unused code (MarcoFalke) -- #8836 `eb18cc1` bitcoin-util-test.py should fail if the output file is empty (jnewbery) -- #8839 `31ab2f8` Avoid ConnectionResetErrors during RPC tests (laanwj) -- #8840 `cbc3fe5` Explicitly set encoding to utf8 when opening text files (laanwj) -- #8841 `3e4abb5` Fix nulldummy test (jl2012) -- #8854 `624a007` Fix race condition in p2p-compactblocks test (sdaftuar) -- #8857 `1f60d45` mininode: Only allow named args in wait_until (MarcoFalke) -- #8860 `0bee740` util: Move wait_bitcoinds() into stop_nodes() (MarcoFalke) -- #8882 `b73f065` Fix race conditions in p2p-compactblocks.py and sendheaders.py (sdaftuar) -- #8904 `cc6f551` Fix compact block shortids for a test case (dagurval) - -### Documentation -- #8754 `0e2c6bd` Target protobuf 2.6 in OS X build notes. (fanquake) -- #8461 `b17a3f9` Document return value of networkhashps for getmininginfo RPC endpoint (jlopp) -- #8512 `156e305` Corrected JSON typo on setban of net.cpp (sevastos) -- #8683 `8a7d7ff` Fix incorrect file name bitcoin.qrc (bitcoinsSG) -- #8891 `5e0dd9e` Update bips.md for Segregated Witness (fanquake) -- #8545 `863ae74` Update git-subtree-check.sh README (MarcoFalke) -- #8607 `486650a` Fix doxygen off-by-one comments, fix typos (MarcoFalke) -- #8560 `c493f43` Fix two VarInt examples in serialize.h (cbarcenas) -- #8737 `084cae9` UndoReadFromDisk works on undo files (rev), not on block files (paveljanik) -- #8625 `0a35573` Clarify statement about parallel jobs in rpc-tests.py (isle2983) -- #8624 `0e6d753` build: Mention curl (MarcoFalke) -- #8604 `b09e13c` build,doc: Update for 0.13.0+ and OpenBSD 5.9 (laanwj) -- #8939 `06d15fb` Update implemented bips for 0.13.1 (sipa) - -### Miscellaneous -- #8742 `d31ac72` Specify Protobuf version 2 in paymentrequest.proto (fanquake) -- #8414,#8558,#8676,#8700,#8701,#8702 Add missing copyright headers (isle2983, kazcw) -- #8899 `4ed2627` Fix wake from sleep issue with Boost 1.59.0 (fanquake) -- #8817 `bcf3806` update bitcoin-tx to output witness data (jnewbery) -- #8513 `4e5fc31` Fix a type error that would not compile on OSX. (JeremyRubin) -- #8392 `30eac2d` Fix several node initialization issues (sipa) -- #8548 `305d8ac` Use `__func__` to get function name for output printing (MarcoFalke) -- #8291 `a987431` [util] CopyrightHolders: Check for untranslated substitution (MarcoFalke) +(to be filled in at release time) Credits ======= Thanks to everyone who directly contributed to this release: -- adlawren -- Alexey Vesnin -- Anders Øyvind Urke-Sætre -- Andrew Chow -- Anthony Towns -- BtcDrak -- Chris Stewart -- Christian Barcenas -- Christian Decker -- Cory Fields -- crowning- -- Dagur Valberg Johannsson -- David A. Harding -- Eric Lombrozo -- Ethan Heilman -- fanquake -- Gaurav Rana -- Gregory Maxwell -- instagibbs -- isle2983 -- Jameson Lopp -- Jeremy Rubin -- jnewbery -- Johnson Lau -- Jonas Schnelli -- jonnynewbs -- Justin Camarena -- Kaz Wesley -- leijurv -- Luke Dashjr -- MarcoFalke -- Marty Jones -- Matt Corallo -- Micha -- Michael Ford -- mruddy -- Pavel Janík -- Pieter Wuille -- rodasmith -- Sev -- Suhas Daftuar -- whythat -- Wladimir J. van der Laan +(to be filled in at release time) As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). diff --git a/doc/release-notes/release-notes-0.13.1.md b/doc/release-notes/release-notes-0.13.1.md new file mode 100644 index 000000000..75c2d61be --- /dev/null +++ b/doc/release-notes/release-notes-0.13.1.md @@ -0,0 +1,410 @@ +Bitcoin Core version 0.13.1 is now available from: + + + +This is a new minor version release, including activation parameters for the +segwit softfork, various bugfixes and performance improvements, as well as +updated translations. + +Please report bugs using the issue tracker at github: + + + +To receive security and update notifications, please subscribe to: + + + +Compatibility +============== + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +an OS initially released in 2001. This means that not even critical security +updates will be released anymore. Without security updates, using a bitcoin +wallet on a XP machine is irresponsible at least. + +In addition to that, with 0.12.x there have been varied reports of Bitcoin Core +randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891) +what the source of these crashes is, but it is likely that upstream +libraries such as Qt are no longer being tested on XP. + +We do not have time nor resources to provide support for an OS that is +end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are +suggested to upgrade to a newer version of Windows, or install an alternative OS +that is supported. + +No attempt is made to prevent installing or running the software on Windows XP, +you can still do so at your own risk, but do not expect it to work: do not +report issues about Windows XP to the issue tracker. + +From 0.13.1 onwards OS X 10.7 is no longer supported. 0.13.0 was intended to work on 10.7+, +but severe issues with the libc++ version on 10.7.x keep it from running reliably. +0.13.1 now requires 10.8+, and will communicate that to 10.7 users, rather than crashing unexpectedly. + +Notable changes +=============== + +Segregated witness soft fork +---------------------------- + +Segregated witness (segwit) is a soft fork that, if activated, will +allow transaction-producing software to separate (segregate) transaction +signatures (witnesses) from the part of the data in a transaction that is +covered by the txid. This provides several immediate benefits: + +- **Elimination of unwanted transaction malleability:** Segregating the witness + allows both existing and upgraded software to calculate the transaction + identifier (txid) of transactions without referencing the witness, which can + sometimes be changed by third-parties (such as miners) or by co-signers in a + multisig spend. This solves all known cases of unwanted transaction + malleability, which is a problem that makes programming Bitcoin wallet + software more difficult and which seriously complicates the design of smart + contracts for Bitcoin. + +- **Capacity increase:** Segwit transactions contain new fields that are not + part of the data currently used to calculate the size of a block, which + allows a block containing segwit transactions to hold more data than allowed + by the current maximum block size. Estimates based on the transactions + currently found in blocks indicate that if all wallets switch to using + segwit, the network will be able to support about 70% more transactions. The + network will also be able to support more of the advanced-style payments + (such as multisig) than it can support now because of the different weighting + given to different parts of a transaction after segwit activates (see the + following section for details). + +- **Weighting data based on how it affects node performance:** Some parts of + each Bitcoin block need to be stored by nodes in order to validate future + blocks; other parts of a block can be immediately forgotten (pruned) or used + only for helping other nodes sync their copy of the block chain. One large + part of the immediately prunable data are transaction signatures (witnesses), + and segwit makes it possible to give a different "weight" to segregated + witnesses to correspond with the lower demands they place on node resources. + Specifically, each byte of a segregated witness is given a weight of 1, each + other byte in a block is given a weight of 4, and the maximum allowed weight + of a block is 4 million. Weighting the data this way better aligns the most + profitable strategy for creating blocks with the long-term costs of block + validation. + +- **Signature covers value:** A simple improvement in the way signatures are + generated in segwit simplifies the design of secure signature generators + (such as hardware wallets), reduces the amount of data the signature + generator needs to download, and allows the signature generator to operate + more quickly. This is made possible by having the generator sign the amount + of bitcoins they think they are spending, and by having full nodes refuse to + accept those signatures unless the amount of bitcoins being spent is exactly + the same as was signed. For non-segwit transactions, wallets instead had to + download the complete previous transactions being spent for every payment + they made, which could be a slow operation on hardware wallets and in other + situations where bandwidth or computation speed was constrained. + +- **Linear scaling of sighash operations:** In 2015 a block was produced that + required about 25 seconds to validate on modern hardware because of the way + transaction signature hashes are performed. Other similar blocks, or blocks + that could take even longer to validate, can still be produced today. The + problem that caused this can't be fixed in a soft fork without unwanted + side-effects, but transactions that opt-in to using segwit will now use a + different signature method that doesn't suffer from this problem and doesn't + have any unwanted side-effects. + +- **Increased security for multisig:** Bitcoin addresses (both P2PKH addresses + that start with a '1' and P2SH addresses that start with a '3') use a hash + function known as RIPEMD-160. For P2PKH addresses, this provides about 160 + bits of security---which is beyond what cryptographers believe can be broken + today. But because P2SH is more flexible, only about 80 bits of security is + provided per address. Although 80 bits is very strong security, it is within + the realm of possibility that it can be broken by a powerful adversary. + Segwit allows advanced transactions to use the SHA256 hash function instead, + which provides about 128 bits of security (that is 281 trillion times as + much security as 80 bits and is equivalent to the maximum bits of security + believed to be provided by Bitcoin's choice of parameters for its Elliptic + Curve Digital Security Algorithm [ECDSA].) + +- **More efficient almost-full-node security** Satoshi Nakamoto's original + Bitcoin paper describes a method for allowing newly-started full nodes to + skip downloading and validating some data from historic blocks that are + protected by large amounts of proof of work. Unfortunately, Nakamoto's + method can't guarantee that a newly-started node using this method will + produce an accurate copy of Bitcoin's current ledger (called the UTXO set), + making the node vulnerable to falling out of consensus with other nodes. + Although the problems with Nakamoto's method can't be fixed in a soft fork, + Segwit accomplishes something similar to his original proposal: it makes it + possible for a node to optionally skip downloading some blockchain data + (specifically, the segregated witnesses) while still ensuring that the node + can build an accurate copy of the UTXO set for the block chain with the most + proof of work. Segwit enables this capability at the consensus layer, but + note that Bitcoin Core does not provide an option to use this capability as + of this 0.13.1 release. + +- **Script versioning:** Segwit makes it easy for future soft forks to allow + Bitcoin users to individually opt-in to almost any change in the Bitcoin + Script language when those users receive new transactions. Features + currently being researched by Bitcoin Core contributors that may use this + capability include support for Schnorr signatures, which can improve the + privacy and efficiency of multisig transactions (or transactions with + multiple inputs), and Merklized Abstract Syntax Trees (MAST), which can + improve the privacy and efficiency of scripts with two or more conditions. + Other Bitcoin community members are studying several other improvements + that can be made using script versioning. + +Activation for the segwit soft fork is being managed using BIP9 +versionbits. Segwit's version bit is bit 1, and nodes will begin +tracking which blocks signal support for segwit at the beginning of the +first retarget period after segwit's start date of 15 November 2016. If +95% of blocks within a 2,016-block retarget period (about two weeks) +signal support for segwit, the soft fork will be locked in. After +another 2,016 blocks, segwit will activate. + +For more information about segwit, please see the [segwit FAQ][], the +[segwit wallet developers guide][] or BIPs [141][BIP141], [143][BIP143], +[144][BIP144], and [145][BIP145]. If you're a miner or mining pool +operator, please see the [versionbits FAQ][] for information about +signaling support for a soft fork. + +[Segwit FAQ]: https://bitcoincore.org/en/2016/01/26/segwit-benefits/ +[segwit wallet developers guide]: https://bitcoincore.org/en/segwit_wallet_dev/ +[BIP141]: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki +[BIP143]: https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki +[BIP144]: https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki +[BIP145]: https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki +[versionbits FAQ]: https://bitcoincore.org/en/2016/06/08/version-bits-miners-faq/ + + +Null dummy soft fork +------------------- + +Combined with the segwit soft fork is an additional change that turns a +long-existing network relay policy into a consensus rule. The +`OP_CHECKMULTISIG` and `OP_CHECKMULTISIGVERIFY` opcodes consume an extra +stack element ("dummy element") after signature validation. The dummy +element is not inspected in any manner, and could be replaced by any +value without invalidating the script. + +Because any value can be used for this dummy element, it's possible for +a third-party to insert data into other people's transactions, changing +the transaction's txid (called transaction malleability) and possibly +causing other problems. + +Since Bitcoin Core 0.10.0, nodes have defaulted to only relaying and +mining transactions whose dummy element was a null value (0x00, also +called OP_0). The null dummy soft fork turns this relay rule into a +consensus rule both for non-segwit transactions and segwit transactions, +so that this method of mutating transactions is permanently eliminated +from the network. + +Signaling for the null dummy soft fork is done by signaling support +for segwit, and the null dummy soft fork will activate at the same time +as segwit. + +For more information, please see [BIP147][]. + +[BIP147]: https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki + +Low-level RPC changes +--------------------- + +- `importprunedfunds` only accepts two required arguments. Some versions accept + an optional third arg, which was always ignored. Make sure to never pass more + than two arguments. + + +Linux ARM builds +---------------- + +With the 0.13.0 release, pre-built Linux ARM binaries were added to the set of +uploaded executables. Additional detail on the ARM architecture targeted by each +is provided below. + +The following extra files can be found in the download directory or torrent: + +- `bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz`: Linux binaries targeting + the 32-bit ARMv7-A architecture. +- `bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz`: Linux binaries targeting + the 64-bit ARMv8-A architecture. + +ARM builds are still experimental. If you have problems on a certain device or +Linux distribution combination please report them on the bug tracker, it may be +possible to resolve them. Note that the device you use must be (backward) +compatible with the architecture targeted by the binary that you use. +For example, a Raspberry Pi 2 Model B or Raspberry Pi 3 Model B (in its 32-bit +execution state) device, can run the 32-bit ARMv7-A targeted binary. However, +no model of Raspberry Pi 1 device can run either binary because they are all +ARMv6 architecture devices that are not compatible with ARMv7-A or ARMv8-A. + +Note that Android is not considered ARM Linux in this context. The executables +are not expected to work out of the box on Android. + + +0.13.1 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### Consensus +- #8636 `9dfa0c8` Implement NULLDUMMY softfork (BIP147) (jl2012) +- #8848 `7a34a46` Add NULLDUMMY verify flag in bitcoinconsensus.h (jl2012) +- #8937 `8b66659` Define start and end time for segwit deployment (sipa) + +### RPC and other APIs +- #8581 `526d2b0` Drop misleading option in importprunedfunds (MarcoFalke) +- #8699 `a5ec248` Remove createwitnessaddress RPC command (jl2012) +- #8780 `794b007` Deprecate getinfo (MarcoFalke) +- #8832 `83ad563` Throw JSONRPCError when utxo set can not be read (MarcoFalke) +- #8884 `b987348` getblockchaininfo help: pruneheight is the lowest, not highest, block (luke-jr) +- #8858 `3f508ed` rpc: Generate auth cookie in hex instead of base64 (laanwj) +- #8951 `7c2bf4b` RPC/Mining: getblocktemplate: Update and fix formatting of help (luke-jr) + +### Block and transaction handling +- #8611 `a9429ca` Reduce default number of blocks to check at startup (sipa) +- #8634 `3e80ab7` Add policy: null signature for failed CHECK(MULTI)SIG (jl2012) +- #8525 `1672225` Do not store witness txn in rejection cache (sipa) +- #8499 `9777fe1` Add several policy limits and disable uncompressed keys for segwit scripts (jl2012) +- #8526 `0027672` Make non-minimal OP_IF/NOTIF argument non-standard for P2WSH (jl2012) +- #8524 `b8c79a0` Precompute sighashes (sipa) +- #8651 `b8c79a0` Predeclare PrecomputedTransactionData as struct (sipa) + +### P2P protocol and network code +- #8740 `42ea51a` No longer send local address in addrMe (laanwj) +- #8427 `69d1cd2` Ignore `notfound` P2P messages (laanwj) +- #8573 `4f84082` Set jonasschnellis dns-seeder filter flag (jonasschnelli) +- #8712 `23feab1` Remove maxuploadtargets recommended minimum (jonasschnelli) +- #8862 `7ae6242` Fix a few cases where messages were sent after requested disconnect (theuni) +- #8393 `fe1975a` Support for compact blocks together with segwit (sipa) +- #8282 `2611ad7` Feeler connections to increase online addrs in the tried table (EthanHeilman) +- #8612 `2215c22` Check for compatibility with download in FindNextBlocksToDownload (sipa) +- #8606 `bbf379b` Fix some locks (sipa) +- #8594 `ab295bb` Do not add random inbound peers to addrman (gmaxwell) +- #8940 `5b4192b` Add x9 service bit support to dnsseed.bluematt.me, seed.bitcoinstats.com (TheBlueMatt, cdecker) +- #8944 `685e4c7` Remove bogus assert on number of oubound connections. (TheBlueMatt) +- #8949 `0dbc48a` Be more agressive in getting connections to peers with relevant services (gmaxwell) + +### Build system +- #8293 `fa5b249` Allow building libbitcoinconsensus without any univalue (luke-jr) +- #8492 `8b0bdd3` Allow building bench_bitcoin by itself (luke-jr) +- #8563 `147003c` Add configure check for -latomic (ajtowns) +- #8626 `ea51b0f` Berkeley DB v6 compatibility fix (netsafe) +- #8520 `75f2065` Remove check for `openssl/ec.h` (laanwj) + +### GUI +- #8481 `d9f0d4e` Fix minimize and close bugs (adlawren) +- #8487 `a37cec5` Persist the datadir after option reset (achow101) +- #8697 `41fd852` Fix op order to append first alert (rodasmith) +- #8678 `8e03382` Fix UI bug that could result in paying unexpected fee (jonasschnelli) +- #8911 `7634d8e` Translate all files, even if wallet disabled (laanwj) +- #8540 `1db3352` Fix random segfault when closing "Choose data directory" dialog (laanwj) +- #7579 `f1c0d78` Show network/chain errors in the GUI (jonasschnelli) + +### Wallet +- #8443 `464dedd` Trivial cleanup of HD wallet changes (jonasschnelli) +- #8539 `cb07f19` CDB: fix debug output (crowning-) +- #8664 `091cdeb` Fix segwit-related wallet bug (sdaftuar) +- #8693 `c6a6291` Add witness address to address book (instagibbs) +- #8765 `6288659` Remove "unused" ThreadFlushWalletDB from removeprunedfunds (jonasschnelli) + +### Tests and QA +- #8713 `ae8c7df` create_cache: Delete temp dir when done (MarcoFalke) +- #8716 `e34374e` Check legacy wallet as well (MarcoFalke) +- #8750 `d6ebe13` Refactor RPCTestHandler to prevent TimeoutExpired (MarcoFalke) +- #8652 `63462c2` remove root test directory for RPC tests (yurizhykin) +- #8724 `da94272` walletbackup: Sync blocks inside the loop (MarcoFalke) +- #8400 `bea02dc` enable rpcbind_test (yurizhykin) +- #8417 `f70be14` Add walletdump RPC test (including HD- & encryption-tests) (jonasschnelli) +- #8419 `a7aa3cc` Enable size accounting in mining unit tests (sdaftuar) +- #8442 `8bb1efd` Rework hd wallet dump test (MarcoFalke) +- #8528 `3606b6b` Update p2p-segwit.py to reflect correct behavior (instagibbs) +- #8531 `a27cdd8` abandonconflict: Use assert_equal (MarcoFalke) +- #8667 `6b07362` Fix SIGHASH_SINGLE bug in test_framework SignatureHash (jl2012) +- #8673 `03b0196` Fix obvious assignment/equality error in test (JeremyRubin) +- #8739 `cef633c` Fix broken sendcmpct test in p2p-compactblocks.py (sdaftuar) +- #8418 `ff893aa` Add tests for compact blocks (sdaftuar) +- #8803 `375437c` Ping regularly in p2p-segwit.py to keep connection alive (jl2012) +- #8827 `9bbe66e` Split up slow RPC calls to avoid pruning test timeouts (sdaftuar) +- #8829 `2a8bca4` Add bitcoin-tx JSON tests (jnewbery) +- #8834 `1dd1783` blockstore: Switch to dumb dbm (MarcoFalke) +- #8835 `d87227d` nulldummy.py: Don't run unused code (MarcoFalke) +- #8836 `eb18cc1` bitcoin-util-test.py should fail if the output file is empty (jnewbery) +- #8839 `31ab2f8` Avoid ConnectionResetErrors during RPC tests (laanwj) +- #8840 `cbc3fe5` Explicitly set encoding to utf8 when opening text files (laanwj) +- #8841 `3e4abb5` Fix nulldummy test (jl2012) +- #8854 `624a007` Fix race condition in p2p-compactblocks test (sdaftuar) +- #8857 `1f60d45` mininode: Only allow named args in wait_until (MarcoFalke) +- #8860 `0bee740` util: Move wait_bitcoinds() into stop_nodes() (MarcoFalke) +- #8882 `b73f065` Fix race conditions in p2p-compactblocks.py and sendheaders.py (sdaftuar) +- #8904 `cc6f551` Fix compact block shortids for a test case (dagurval) + +### Documentation +- #8754 `0e2c6bd` Target protobuf 2.6 in OS X build notes. (fanquake) +- #8461 `b17a3f9` Document return value of networkhashps for getmininginfo RPC endpoint (jlopp) +- #8512 `156e305` Corrected JSON typo on setban of net.cpp (sevastos) +- #8683 `8a7d7ff` Fix incorrect file name bitcoin.qrc (bitcoinsSG) +- #8891 `5e0dd9e` Update bips.md for Segregated Witness (fanquake) +- #8545 `863ae74` Update git-subtree-check.sh README (MarcoFalke) +- #8607 `486650a` Fix doxygen off-by-one comments, fix typos (MarcoFalke) +- #8560 `c493f43` Fix two VarInt examples in serialize.h (cbarcenas) +- #8737 `084cae9` UndoReadFromDisk works on undo files (rev), not on block files (paveljanik) +- #8625 `0a35573` Clarify statement about parallel jobs in rpc-tests.py (isle2983) +- #8624 `0e6d753` build: Mention curl (MarcoFalke) +- #8604 `b09e13c` build,doc: Update for 0.13.0+ and OpenBSD 5.9 (laanwj) +- #8939 `06d15fb` Update implemented bips for 0.13.1 (sipa) + +### Miscellaneous +- #8742 `d31ac72` Specify Protobuf version 2 in paymentrequest.proto (fanquake) +- #8414,#8558,#8676,#8700,#8701,#8702 Add missing copyright headers (isle2983, kazcw) +- #8899 `4ed2627` Fix wake from sleep issue with Boost 1.59.0 (fanquake) +- #8817 `bcf3806` update bitcoin-tx to output witness data (jnewbery) +- #8513 `4e5fc31` Fix a type error that would not compile on OSX. (JeremyRubin) +- #8392 `30eac2d` Fix several node initialization issues (sipa) +- #8548 `305d8ac` Use `__func__` to get function name for output printing (MarcoFalke) +- #8291 `a987431` [util] CopyrightHolders: Check for untranslated substitution (MarcoFalke) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- adlawren +- Alexey Vesnin +- Anders Øyvind Urke-Sætre +- Andrew Chow +- Anthony Towns +- BtcDrak +- Chris Stewart +- Christian Barcenas +- Christian Decker +- Cory Fields +- crowning- +- Dagur Valberg Johannsson +- David A. Harding +- Eric Lombrozo +- Ethan Heilman +- fanquake +- Gaurav Rana +- Gregory Maxwell +- instagibbs +- isle2983 +- Jameson Lopp +- Jeremy Rubin +- jnewbery +- Johnson Lau +- Jonas Schnelli +- jonnynewbs +- Justin Camarena +- Kaz Wesley +- leijurv +- Luke Dashjr +- MarcoFalke +- Marty Jones +- Matt Corallo +- Micha +- Michael Ford +- mruddy +- Pavel Janík +- Pieter Wuille +- rodasmith +- Sev +- Suhas Daftuar +- whythat +- Wladimir J. van der Laan + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). From 82905069bfd763f16a63649eb51ed3a566bca2c5 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 26 Oct 2016 13:03:30 -0400 Subject: [PATCH 09/91] [qa] Test that invalid compactblocks don't result in ban --- qa/rpc-tests/p2p-compactblocks.py | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 131654c33..9ecced0dd 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -708,6 +708,33 @@ def test_end_to_end_block_relay(self, node, listeners): l.last_cmpctblock.header_and_shortids.header.calc_sha256() assert_equal(l.last_cmpctblock.header_and_shortids.header.sha256, block.sha256) + # Test that we don't get disconnected if we relay a compact block with valid header, + # but invalid transactions. + def test_invalid_tx_in_compactblock(self, node, test_node, use_segwit): + assert(len(self.utxos)) + utxo = self.utxos[0] + + block = self.build_block_with_transactions(node, utxo, 5) + del block.vtx[3] + block.hashMerkleRoot = block.calc_merkle_root() + if use_segwit: + # If we're testing with segwit, also drop the coinbase witness, + # but include the witness commitment. + add_witness_commitment(block) + block.vtx[0].wit.vtxinwit = [] + block.solve() + + # Now send the compact block with all transactions prefilled, and + # verify that we don't get disconnected. + comp_block = HeaderAndShortIDs() + comp_block.initialize_from_block(block, prefill_list=[0, 1, 2, 3, 4], use_witness=use_segwit) + msg = msg_cmpctblock(comp_block.to_p2p()) + test_node.send_and_ping(msg) + + # Check that the tip didn't advance + assert(int(node.getbestblockhash(), 16) is not block.sha256) + test_node.sync_with_ping() + # Helper for enabling cb announcements # Send the sendcmpct request and sync headers def request_cb_announcements(self, peer, node, version): @@ -798,6 +825,11 @@ def run_test(self): self.test_end_to_end_block_relay(self.nodes[0], [self.segwit_node, self.test_node, self.old_node]) self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node]) + print("\tTesting handling of invalid compact blocks...") + self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False) + self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False) + self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False) + # Advance to segwit activation print ("\nAdvancing to segwit activation\n") self.activate_segwit(self.nodes[1]) @@ -844,6 +876,11 @@ def run_test(self): self.request_cb_announcements(self.segwit_node, self.nodes[1], 2) self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node]) + print("\tTesting handling of invalid compact blocks...") + self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False) + self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, True) + self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, True) + print("\tTesting invalid index in cmpctblock message...") self.test_invalid_cmpctblock_message() From 015865ee9e5dd450ceb6cece489f924aaa1137e3 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Mon, 31 Oct 2016 10:03:49 -0400 Subject: [PATCH 10/91] Fix compact block handling to not ban if block is invalid --- src/blockencodings.cpp | 2 +- src/blockencodings.h | 2 ++ src/main.cpp | 47 ++++++++++++++++++++++++++------------- src/main.h | 2 +- src/rpc/mining.cpp | 4 ++-- src/test/miner_tests.cpp | 2 +- src/test/test_bitcoin.cpp | 2 +- 7 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index 93d3fa372..737102f16 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -167,7 +167,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector< // check its own merkle root and cache that check. if (state.CorruptionPossible()) return READ_STATUS_FAILED; // Possible Short ID collision - return READ_STATUS_INVALID; + return READ_STATUS_CHECKBLOCK_FAILED; } LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool and %lu txn requested\n", header.GetHash().ToString(), prefilled_count, mempool_count, vtx_missing.size()); diff --git a/src/blockencodings.h b/src/blockencodings.h index 2f87c6d31..cab847ee3 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -124,6 +124,8 @@ typedef enum ReadStatus_t READ_STATUS_OK, READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap READ_STATUS_FAILED, // Failed to process object + READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a + // failure in CheckBlock. } ReadStatus; class CBlockHeaderAndShortTxIDs { diff --git a/src/main.cpp b/src/main.cpp index 61d0aaf0b..850380abb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -178,8 +178,10 @@ namespace { * Sources of received blocks, saved to be able to send them reject * messages or ban them when processing happens afterwards. Protected by * cs_main. + * Set mapBlockSource[hash].second to false if the node should not be + * punished if the block is invalid. */ - map mapBlockSource; + map> mapBlockSource; /** * Filter for transactions that were recently rejected by @@ -1885,13 +1887,13 @@ void static InvalidChainFound(CBlockIndex* pindexNew) void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { int nDoS = 0; if (state.IsInvalid(nDoS)) { - std::map::iterator it = mapBlockSource.find(pindex->GetBlockHash()); - if (it != mapBlockSource.end() && State(it->second)) { + std::map>::iterator it = mapBlockSource.find(pindex->GetBlockHash()); + if (it != mapBlockSource.end() && State(it->second.first)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()}; - State(it->second)->rejects.push_back(reject); - if (nDoS > 0) - Misbehaving(it->second, nDoS); + State(it->second.first)->rejects.push_back(reject); + if (nDoS > 0 && it->second.second) + Misbehaving(it->second.first, nDoS); } } if (!state.CorruptionPossible()) { @@ -3761,7 +3763,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned } -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid) { { LOCK(cs_main); @@ -3773,7 +3775,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C bool fNewBlock = false; bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp, &fNewBlock); if (pindex && pfrom) { - mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); + mapBlockSource[pindex->GetBlockHash()] = std::make_pair(pfrom->GetId(), fMayBanPeerIfInvalid); if (fNewBlock) pfrom->nLastBlockTime = GetTime(); } CheckBlockIndex(chainparams.GetConsensus()); @@ -4717,7 +4719,6 @@ std::string GetWarnings(const std::string& strFor) ////////////////////////////////////////////////////////////////////////////// -// // Messages // @@ -5791,17 +5792,33 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash)); pfrom->PushMessage(NetMsgType::GETDATA, invs); } else { + // Block is either okay, or possibly we received + // READ_STATUS_CHECKBLOCK_FAILED. + // Note that CheckBlock can only fail for one of a few reasons: + // 1. bad-proof-of-work (impossible here, because we've already + // accepted the header) + // 2. merkleroot doesn't match the transactions given (already + // caught in FillBlock with READ_STATUS_FAILED, so + // impossible here) + // 3. the block is otherwise invalid (eg invalid coinbase, + // block is too big, too many legacy sigops, etc). + // So if CheckBlock failed, #3 is the only possibility. + // Under BIP 152, we don't DoS-ban unless proof of work is + // invalid (we don't require all the stateless checks to have + // been run). This is handled below, so just treat this as + // though the block was successfully read, and rely on the + // handling in ProcessNewBlock to ensure the block index is + // updated, reject messages go out, etc. CValidationState state; - ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL); + // BIP 152 permits peers to relay compact blocks after validating + // the header only; we should not punish peers if the block turns + // out to be invalid. + ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, false); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash()); - if (nDoS > 0) { - LOCK(cs_main); - Misbehaving(pfrom->GetId(), nDoS); - } } } } @@ -5968,7 +5985,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, true); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes diff --git a/src/main.h b/src/main.h index 0ca13d82d..daf884337 100644 --- a/src/main.h +++ b/src/main.h @@ -222,7 +222,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 14a61a55d..e6901bc77 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr coinbaseScript, int nG continue; } CValidationState state; - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, false)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -760,7 +760,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, false); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 15fceb963..70ba70779 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, false)); BOOST_CHECK(state.IsValid()); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 056f2982c..09f9a362d 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -118,7 +118,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; CValidationState state; - ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, false); CBlock result = block; delete pblocktemplate; From e8ef50ba51968da67a36c9fae6938d868b434da2 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Tue, 1 Nov 2016 11:12:43 -0400 Subject: [PATCH 11/91] Bump the protocol version to distinguish new banning behavior. This allows future software that would relay compact blocks before full validation to announce only to peers that will not ban if the block turns out to be invalid. --- src/version.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 68ccd6d37..497f82be2 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70014; +static const int PROTOCOL_VERSION = 70015; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -42,4 +42,7 @@ static const int FEEFILTER_VERSION = 70013; //! shord-id-based block download starts with this version static const int SHORT_IDS_BLOCKS_VERSION = 70014; +//! not banning for invalid compact blocks starts with this version +static const int INVALID_CB_NO_BAN_VERSION = 70015; + #endif // BITCOIN_VERSION_H From 3107280e14f7ca63c693937aac490794ae746a09 Mon Sep 17 00:00:00 2001 From: mrbandrews Date: Tue, 15 Nov 2016 15:37:46 -0500 Subject: [PATCH 12/91] [qa] add assert_raises_message to check specific error message Github-Pull: #9168 Rebased-From: 307acdd3df03082295ac0f7fe9eba7dd35973bc4 --- qa/rpc-tests/test_framework/util.py | 8 ++++++-- qa/rpc-tests/wallet.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index 47cebf4f6..c5f270591 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -508,10 +508,14 @@ def assert_greater_than(thing1, thing2): raise AssertionError("%s <= %s"%(str(thing1),str(thing2))) def assert_raises(exc, fun, *args, **kwds): + assert_raises_message(exc, None, fun, *args, **kwds) + +def assert_raises_message(exc, message, fun, *args, **kwds): try: fun(*args, **kwds) - except exc: - pass + except exc as e: + if message is not None and message not in e.error['message']: + raise AssertionError("Expected substring not found:"+e.error['message']) except Exception as e: raise AssertionError("Unexpected exception raised: "+type(e).__name__) else: diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index e43f6ea5d..3c0dc0f4e 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -71,7 +71,7 @@ def run_test (self): unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} self.nodes[2].lockunspent(False, [unspent_0]) - assert_raises(JSONRPCException, self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) + assert_raises_message(JSONRPCException, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) From 1d4c884cd325150c68b8b129e4dc18a933866509 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 2 Nov 2016 09:46:55 -0400 Subject: [PATCH 13/91] [qa] Increase wallet-dump RPC timeout Increase wallet-dump RPC timeout from 30 seconds to 1 minute. This avoids a timeout error that seemed to happen regularly (around 50% of builds) on a particular jenkins server during the first getnewaddress RPC call made by the test. The failing stack trace looked like: Unexpected exception caught during testing: timeout('timed out',) File ".../bitcoin/qa/rpc-tests/test_framework/test_framework.py", line 146, in main self.run_test() File ".../bitcoin/qa/rpc-tests/wallet-dump.py", line 73, in run_test addr = self.nodes[0].getnewaddress() File ".../bitcoin/qa/rpc-tests/test_framework/coverage.py", line 49, in __call__ return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs) File ".../bitcoin/qa/rpc-tests/test_framework/authproxy.py", line 145, in __call__ response = self._request('POST', self.__url.path, postdata.encode('utf-8')) File ".../bitcoin/qa/rpc-tests/test_framework/authproxy.py", line 121, in _request return self._get_response() File ".../bitcoin/qa/rpc-tests/test_framework/authproxy.py", line 160, in _get_response http_response = self.__conn.getresponse() File "/usr/lib/python3.4/http/client.py", line 1171, in getresponse response.begin() File "/usr/lib/python3.4/http/client.py", line 351, in begin version, status, reason = self._read_status() File "/usr/lib/python3.4/http/client.py", line 313, in _read_status line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") File "/usr/lib/python3.4/socket.py", line 374, in readinto return self._sock.recv_into(b) Github-Pull: #9077 Rebased-From: 8463aaa63c5ac76421c4d2754ea9e17a31584c93 --- qa/rpc-tests/test_framework/util.py | 4 ++-- qa/rpc-tests/wallet-dump.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index c5f270591..bf3f2b2db 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -327,7 +327,7 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= return proxy -def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None): +def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): """ Start multiple bitcoinds, return RPC connections to them """ @@ -336,7 +336,7 @@ def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None): rpcs = [] try: for i in range(num_nodes): - rpcs.append(start_node(i, dirname, extra_args[i], rpchost, binary=binary[i])) + rpcs.append(start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i])) except: # If one node failed to start, stop the others stop_nodes(rpcs) raise diff --git a/qa/rpc-tests/wallet-dump.py b/qa/rpc-tests/wallet-dump.py index a37096a40..c6dc2e3d1 100755 --- a/qa/rpc-tests/wallet-dump.py +++ b/qa/rpc-tests/wallet-dump.py @@ -61,7 +61,11 @@ def __init__(self): self.extra_args = [["-keypool=90"]] def setup_network(self, split=False): - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + # Use 1 minute timeout because the initial getnewaddress RPC can take + # longer than the default 30 seconds due to an expensive + # CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in + # the test often takes even longer. + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) def run_test (self): tmpdir = self.options.tmpdir From da4926b1d28c600076d3eb35df60981298194697 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 2 Nov 2016 15:08:54 -0400 Subject: [PATCH 14/91] [qa] Add more helpful RPC timeout message Replace previous timeout('timed out',) exception with more detailed error. Github-Pull: #9077 Rebased-From: e89614b6abf28d7fe201c3db44a0df6e4db6de03 --- qa/rpc-tests/test_framework/authproxy.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py index 1a94bf5fe..7b051545c 100644 --- a/qa/rpc-tests/test_framework/authproxy.py +++ b/qa/rpc-tests/test_framework/authproxy.py @@ -42,6 +42,7 @@ import decimal import json import logging +import socket try: import urllib.parse as urlparse except ImportError: @@ -157,7 +158,15 @@ def _batch(self, rpc_call_list): return self._request('POST', self.__url.path, postdata.encode('utf-8')) def _get_response(self): - http_response = self.__conn.getresponse() + try: + http_response = self.__conn.getresponse() + except socket.timeout as e: + raise JSONRPCException({ + 'code': -344, + 'message': '%r RPC took longer than %f seconds. Consider ' + 'using larger timeout for calls that take ' + 'longer to return.' % (self._service_name, + self.__conn.timeout)}) if http_response is None: raise JSONRPCException({ 'code': -342, 'message': 'missing HTTP response from server'}) From dccdc3aa34218eecd4a37988857b5d4f3dd884ef Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 18 Nov 2016 13:08:30 +0100 Subject: [PATCH 15/91] test: Fix use-after-free in scheduler tests Make a copy of the boost time-point to wait for, otherwise the head of the queue may be deleted by another thread while this one is waiting, while the boost function still has a reference to it. Although this problem is in non-test code, this is not an actual problem outside of the tests because we use the thread scheduler with only one service thread, so there will never be threads fighting at the head of the queue. The old boost fallback escapes this problem because it passes a scalar value to wait_until instead of a const object reference. Found by running the tests in LLVM-4.0-master asan. Github-Pull: #9186 Rebased-From: 12519bf62b8c49b1c1744eca6ea5b3162a61f962 --- src/scheduler.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 52777b61f..27c03f154 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -54,9 +54,10 @@ void CScheduler::serviceQueue() #else // Some boost versions have a conflicting overload of wait_until that returns void. // Explicitly use a template here to avoid hitting that overload. - while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { - // Keep waiting until timeout + while (!shouldStop() && !taskQueue.empty()) { + boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; + if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) + break; // Exit loop after timeout, it means we reached the time of the event } #endif // If there are multiple threads, the queue can empty while we're waiting (another From eca9b4653788570c25e646dcdfa9ba088e89f20e Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Mon, 14 Nov 2016 09:58:30 -0500 Subject: [PATCH 16/91] [qa] Wait for specific block announcement in p2p-compactblocks Change check_announcement_of_new_block() to wait specifically for the announcement of the newly created block, instead of waiting for any announcement at all. A difficult to reproduce failure in check_announcement_of_new_block() that happened in a travis build (https://travis-ci.org/bitcoin/bitcoin/jobs/175198367) might have happened because an older announcement was mistaken for the expected one. The error looked like: Assertion failed: Failed File ".../bitcoin/qa/rpc-tests/test_framework/test_framework.py", line 145, in main self.run_test() File ".../bitcoin/build/../qa/rpc-tests/p2p-compactblocks.py", line 787, in run_test self.test_sendcmpct(self.nodes[1], self.segwit_node, 2, old_node=self.old_node) File ".../bitcoin/build/../qa/rpc-tests/p2p-compactblocks.py", line 201, in test_sendcmpct check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None and p.last_inv is not None) File ".../bitcoin/build/../qa/rpc-tests/p2p-compactblocks.py", line 194, in check_announcement_of_new_block assert(predicate(peer)) This commit also changes the assertion failed message above to include more detailed information for debug. Github-Pull: #9159 Rebased-From: dfa44d1b07a6d1022005dba63dd6372739eee8a0 --- qa/rpc-tests/p2p-compactblocks.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 9ecced0dd..c20cbede5 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -186,12 +186,15 @@ def received_sendcmpct(): def check_announcement_of_new_block(node, peer, predicate): peer.clear_block_announcement() - node.generate(1) - got_message = wait_until(lambda: peer.block_announced, timeout=30) + block_hash = int(node.generate(1)[0], 16) + peer.wait_for_block_announcement(block_hash, timeout=30) assert(peer.block_announced) assert(got_message) + with mininode_lock: - assert(predicate(peer)) + assert predicate(peer), ( + "block_hash={!r}, cmpctblock={!r}, inv={!r}".format( + block_hash, peer.last_cmpctblock, peer.last_inv)) # We shouldn't get any block announcements via cmpctblock yet. check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None) From 2ba5d784276783716bbf27b458514c4c3f44f4b6 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Mon, 24 Oct 2016 15:33:14 -0400 Subject: [PATCH 17/91] [qa] Fix bug in compactblocks v2 merge Bug caused the wait_for_block_announcement to be called on the wrong node, leading to nondeterminism and occasional test failures. Bug was introduced in merge commit: d075479 Merge #8882: [qa] Fix race conditions in p2p-compactblocks.py and sendheaders.py Underlying commits which conflicted were: 27acfc1 [qa] Update p2p-compactblocks.py for compactblocks v2 6976db2 [qa] Another attempt to fix race condition in p2p-compactblocks.py The first commit changed the test_compactblock_construction function signature and second commit added code which wasn't updated during the merge to use the new arguments. Suhas Daftuar noticed the bug and suggested the fix. Github-Pull: #9058 Rebased-From: 47e9659ecfbe07077a4564591095bd5510e0f917 --- qa/rpc-tests/p2p-compactblocks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index c20cbede5..0abb9f986 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -303,8 +303,8 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a assert(segwit_tx_generated) # check that our test is not broken # Wait until we've seen the block announcement for the resulting tip - tip = int(self.nodes[0].getbestblockhash(), 16) - assert(self.test_node.wait_for_block_announcement(tip)) + tip = int(node.getbestblockhash(), 16) + assert(test_node.wait_for_block_announcement(tip)) # Now mine a block, and look at the resulting compact block. test_node.clear_block_announcement() From 286e548d87266f3b394d75182f04fb701b2263e8 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 26 Oct 2016 14:15:16 -0400 Subject: [PATCH 18/91] [qa] Fix stale data bug in test_compactblocks_not_at_tip Clear test_node.last_block before requesting blocks in the compactblocks_not_at_tip test so comparisons won't fail if a blocks were received before the test started. The bug doesn't currently cause any problems due to the order tests run, but this will change in the next commit. Github-Pull: #9058 Rebased-From: 55bfddcabbf9e8a3743f77167ba4a43aaba9f948 --- qa/rpc-tests/p2p-compactblocks.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 0abb9f986..249afec2b 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -651,6 +651,8 @@ def test_compactblocks_not_at_tip(self, node, test_node): node.generate(1) wait_until(test_node.received_block_announcement, timeout=30) test_node.clear_block_announcement() + with mininode_lock: + test_node.last_block = None test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))])) success = wait_until(lambda: test_node.last_block is not None, timeout=30) assert(success) From 36e3b951039b98508badaafa0bbec166c22900d3 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 21 Jun 2016 13:08:29 -0700 Subject: [PATCH 19/91] Dont remove a "preferred" cmpctblock peer if they provide a block Github-Pull: #8637 Rebased-From: 02a337defdd854efc78ecba6d1fb19cb1c075f16 --- src/main.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 96734b839..3436caaf1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -495,9 +495,13 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf return; } if (nodestate->fProvidesHeaderAndIDs) { - BOOST_FOREACH(const NodeId nodeid, lNodesAnnouncingHeaderAndIDs) - if (nodeid == pfrom->GetId()) + for (std::list::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) { + if (*it == pfrom->GetId()) { + lNodesAnnouncingHeaderAndIDs.erase(it); + lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId()); return; + } + } bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = (nLocalServices & NODE_WITNESS) ? 2 : 1; if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { @@ -5727,6 +5731,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } + if (!fAlreadyInFlight && mapBlocksInFlight.size() == 1 && pindex->pprev->IsValid(BLOCK_VALID_CHAIN)) { + // We seem to be rather well-synced, so it appears pfrom was the first to provide us + // with this block! Let's get them to announce using compact blocks in the future. + MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman); + } + BlockTransactionsRequest req; for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) { if (!partialBlock.IsTxAvailable(i)) From 76ba1c973948a33bbf87d13c4bd2f2b81fb466a2 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 21 Jun 2016 16:28:38 -0700 Subject: [PATCH 20/91] More agressively filter compact block requests Unit test adaptations by Pieter Wuille. Github-Pull: #8637 Rebased-From: fe998e962dc015978f104b782afb7daec3c4d4df --- qa/rpc-tests/p2p-compactblocks.py | 4 ++-- src/main.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 249afec2b..402966978 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -594,7 +594,7 @@ def test_incorrect_blocktxn_response(self, node, test_node, version): def test_getblocktxn_handler(self, node, test_node, version): # bitcoind won't respond for blocks whose height is more than 15 blocks # deep. - MAX_GETBLOCKTXN_DEPTH = 15 + MAX_GETBLOCKTXN_DEPTH = 10 chain_height = node.getblockcount() current_height = chain_height while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH): @@ -635,7 +635,7 @@ def test_getblocktxn_handler(self, node, test_node, version): def test_compactblocks_not_at_tip(self, node, test_node): # Test that requesting old compactblocks doesn't work. - MAX_CMPCTBLOCK_DEPTH = 11 + MAX_CMPCTBLOCK_DEPTH = 6 new_blocks = [] for i in range(MAX_CMPCTBLOCK_DEPTH): test_node.clear_block_announcement() diff --git a/src/main.cpp b/src/main.cpp index 3436caaf1..2e09b6cf7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4855,7 +4855,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // and we don't feel like constructing the object for them, so // instead we respond with the full, non-compact block. bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness; - if (mi->second->nHeight >= chainActive.Height() - 10) { + if (CanDirectFetch(Params().GetConsensus()) && mi->second->nHeight >= chainActive.Height() - 5) { CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness); pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock); } else @@ -5401,8 +5401,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } - if (it->second->nHeight < chainActive.Height() - 15) { - LogPrint("net", "Peer %d sent us a getblocktxn for a block > 15 deep", pfrom->id); + if (it->second->nHeight < chainActive.Height() - 10) { + LogPrint("net", "Peer %d sent us a getblocktxn for a block > 10 deep", pfrom->id); return true; } From 3d23a0eaa3cfa349833e42345daf954e9530bdfd Mon Sep 17 00:00:00 2001 From: instagibbs Date: Wed, 22 Jun 2016 08:18:22 -0400 Subject: [PATCH 21/91] Add cmpctblock to debug help list Github-Pull: #8637 Rebased-From: b2e93a343ec2dc7d255b970e6ee45e9c390f7ed0 --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index f2b13b627..eab8de8d0 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -412,7 +412,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified bip9 deployment (regtest-only)"); } - string debugCategories = "addrman, alert, bench, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below + string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + From 2cad5db6f752ad8fa2d047b67a137de76eb9c982 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 31 Aug 2016 17:35:59 +0200 Subject: [PATCH 22/91] Align constant names for maximum compact block / blocktxn depth Github-Pull: #8637 Rebased-From: 3ac6de0a045cc9b2047ceb19af970e7ffbf905fa --- qa/rpc-tests/p2p-compactblocks.py | 4 ++-- src/main.cpp | 6 +++--- src/main.h | 5 +++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 402966978..0c73032c9 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -635,9 +635,9 @@ def test_getblocktxn_handler(self, node, test_node, version): def test_compactblocks_not_at_tip(self, node, test_node): # Test that requesting old compactblocks doesn't work. - MAX_CMPCTBLOCK_DEPTH = 6 + MAX_CMPCTBLOCK_DEPTH = 5 new_blocks = [] - for i in range(MAX_CMPCTBLOCK_DEPTH): + for i in range(MAX_CMPCTBLOCK_DEPTH + 1): test_node.clear_block_announcement() new_blocks.append(node.generate(1)[0]) wait_until(test_node.received_block_announcement, timeout=30) diff --git a/src/main.cpp b/src/main.cpp index 2e09b6cf7..db020a449 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4855,7 +4855,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // and we don't feel like constructing the object for them, so // instead we respond with the full, non-compact block. bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness; - if (CanDirectFetch(Params().GetConsensus()) && mi->second->nHeight >= chainActive.Height() - 5) { + if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness); pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock); } else @@ -5401,8 +5401,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } - if (it->second->nHeight < chainActive.Height() - 10) { - LogPrint("net", "Peer %d sent us a getblocktxn for a block > 10 deep", pfrom->id); + if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) { + LogPrint("net", "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->id, MAX_BLOCKTXN_DEPTH); return true; } diff --git a/src/main.h b/src/main.h index daf884337..024f35cd3 100644 --- a/src/main.h +++ b/src/main.h @@ -89,6 +89,11 @@ static const unsigned int BLOCK_STALLING_TIMEOUT = 2; /** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ static const unsigned int MAX_HEADERS_RESULTS = 2000; +/** Maximum depth of blocks we're willing to serve as compact blocks to peers + * when requested. For older blocks, a regular BLOCK response will be sent. */ +static const int MAX_CMPCTBLOCK_DEPTH = 5; +/** Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for. */ +static const int MAX_BLOCKTXN_DEPTH = 10; /** Size of the "block download window": how far ahead of our current height do we fetch? * Larger windows tolerate larger download speed differences between peer, but increase the potential * degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning From e8461666ecd7f0f89fba92a377c0f8beffa233e9 Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Wed, 26 Oct 2016 14:53:18 -0400 Subject: [PATCH 23/91] Modify getblocktxn handler not to drop requests for old blocks The current getblocktxn implementation drops and ignores requests for old blocks, which causes occasional sync_block timeouts during the p2p-compactblocks.py test as reported in https://github.com/bitcoin/bitcoin/issues/8842. The p2p-compactblocks.py test setup creates many new blocks in a short period of time, which can lead to getblocktxn requests for blocks below the hardcoded depth limit of 10 blocks. This commit changes the getblocktxn handler not to ignore these requests, so the peer nodes in the test setup will reliably be able to sync. The protocol change is documented in BIP-152 update "Allow block responses to getblocktxn requests" at https://github.com/bitcoin/bips/pull/469. The protocol change is not expected to affect nodes running outside the test environment, because there shouldn't normally be lots of new blocks being rapidly added that need to be synced. Github-Pull: #9058 Rebased-From: dac53b58b555183ccc0d5e64c428528267cd98b3 Github-Pull: #9160 Rebased-From: ec34648766c4052816e4072cc61ad429430bcfd9 --- qa/rpc-tests/p2p-compactblocks.py | 12 +++++++++--- src/main.cpp | 14 +++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 0c73032c9..e0b72e684 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -592,8 +592,8 @@ def test_incorrect_blocktxn_response(self, node, test_node, version): assert_equal(int(node.getbestblockhash(), 16), block.sha256) def test_getblocktxn_handler(self, node, test_node, version): - # bitcoind won't respond for blocks whose height is more than 15 blocks - # deep. + # bitcoind will not send blocktxn responses for blocks whose height is + # more than 10 blocks deep. MAX_GETBLOCKTXN_DEPTH = 10 chain_height = node.getblockcount() current_height = chain_height @@ -626,11 +626,17 @@ def test_getblocktxn_handler(self, node, test_node, version): test_node.last_blocktxn = None current_height -= 1 - # Next request should be ignored, as we're past the allowed depth. + # Next request should send a full block response, as we're past the + # allowed depth for a blocktxn response. block_hash = node.getblockhash(current_height) msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0]) + with mininode_lock: + test_node.last_block = None + test_node.last_blocktxn = None test_node.send_and_ping(msg) with mininode_lock: + test_node.last_block.block.calc_sha256() + assert_equal(test_node.last_block.block.sha256, int(block_hash, 16)) assert_equal(test_node.last_blocktxn, None) def test_compactblocks_not_at_tip(self, node, test_node): diff --git a/src/main.cpp b/src/main.cpp index db020a449..191bcff4c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5402,7 +5402,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } if (it->second->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("net", "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->id, 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); + ProcessGetData(pfrom, chainparams.GetConsensus()); return true; } @@ -5734,7 +5746,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (!fAlreadyInFlight && mapBlocksInFlight.size() == 1 && pindex->pprev->IsValid(BLOCK_VALID_CHAIN)) { // We seem to be rather well-synced, so it appears pfrom was the first to provide us // with this block! Let's get them to announce using compact blocks in the future. - MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman); + MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom); } BlockTransactionsRequest req; From 94531b53509470e01dcbd90275577cb37a794fa8 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 28 Nov 2016 17:13:51 +0100 Subject: [PATCH 24/91] torcontrol: Explicitly request RSA1024 private key When generating a new service key, explicitly request a RSA1024 one. The bitcoin P2P protocol has no support for the longer hidden service names that will come with ed25519 keys, until it does, we depend on the old hidden service type so make this explicit. See #9214. Rebased-From: 7d3b627395582ae7c9d54ebdbc68096d7042162b Github-Pull: #9234 --- src/torcontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 0d6b65567..261da728a 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -469,7 +469,7 @@ void TorController::auth_cb(TorControlConnection& conn, const TorControlReply& r // Finally - now create the service if (private_key.empty()) // No private key, generate one - private_key = "NEW:BEST"; + private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214 // Request hidden service, redirect port. // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient // choice. TODO; refactor the shutdown sequence some day. From b172377857f9b5a0b2f43e0e57be9acf82a6c50a Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 1 Dec 2016 14:31:38 -0800 Subject: [PATCH 25/91] Revert "Use async name resolving to improve net thread responsiveness" This reverts commit caf6150e9785da408f1e603ae70eae25b5202d98. getaddrinfo_a has a nasty tendency to segfault internally in its background thread, on every version of glibc I tested, especially under helgrind. See https://sourceware.org/bugzilla/show_bug.cgi?id=20874 Github-Pull: #9229 Rebased-From: 10ae7a7b2316f8052ec58ef237ce6dd987300900 --- configure.ac | 2 -- src/netbase.cpp | 48 +----------------------------------------------- 2 files changed, 1 insertion(+), 49 deletions(-) diff --git a/configure.ac b/configure.ac index 97b330449..b091c74b7 100644 --- a/configure.ac +++ b/configure.ac @@ -527,8 +527,6 @@ if test x$TARGET_OS = xdarwin; then fi AC_CHECK_HEADERS([endian.h sys/endian.h byteswap.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h sys/prctl.h]) -AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])]) -AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])]) AC_CHECK_DECLS([strnlen]) diff --git a/src/netbase.cpp b/src/netbase.cpp index e2a516986..ebf30d43e 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -96,30 +96,9 @@ bool static LookupIntern(const char *pszName, std::vector& vIP, unsign } } -#ifdef HAVE_GETADDRINFO_A - struct in_addr ipv4_addr; -#ifdef HAVE_INET_PTON - if (inet_pton(AF_INET, pszName, &ipv4_addr) > 0) { - vIP.push_back(CNetAddr(ipv4_addr)); - return true; - } - - struct in6_addr ipv6_addr; - if (inet_pton(AF_INET6, pszName, &ipv6_addr) > 0) { - vIP.push_back(CNetAddr(ipv6_addr)); - return true; - } -#else - ipv4_addr.s_addr = inet_addr(pszName); - if (ipv4_addr.s_addr != INADDR_NONE) { - vIP.push_back(CNetAddr(ipv4_addr)); - return true; - } -#endif -#endif - struct addrinfo aiHint; memset(&aiHint, 0, sizeof(struct addrinfo)); + aiHint.ai_socktype = SOCK_STREAM; aiHint.ai_protocol = IPPROTO_TCP; aiHint.ai_family = AF_UNSPEC; @@ -128,33 +107,8 @@ bool static LookupIntern(const char *pszName, std::vector& vIP, unsign #else aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; #endif - struct addrinfo *aiRes = NULL; -#ifdef HAVE_GETADDRINFO_A - struct gaicb gcb, *query = &gcb; - memset(query, 0, sizeof(struct gaicb)); - gcb.ar_name = pszName; - gcb.ar_request = &aiHint; - int nErr = getaddrinfo_a(GAI_NOWAIT, &query, 1, NULL); - if (nErr) - return false; - - do { - // Should set the timeout limit to a reasonable value to avoid - // generating unnecessary checking call during the polling loop, - // while it can still response to stop request quick enough. - // 2 seconds looks fine in our situation. - struct timespec ts = { 2, 0 }; - gai_suspend(&query, 1, &ts); - boost::this_thread::interruption_point(); - - nErr = gai_error(query); - if (0 == nErr) - aiRes = query->ar_result; - } while (nErr == EAI_INPROGRESS); -#else int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); -#endif if (nErr) return false; From d1b4da9259ded1776479ac97b30d8eaa6747ee71 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Tue, 15 Nov 2016 16:12:17 -0500 Subject: [PATCH 26/91] build: fix qt5.7 build under macOS OBJCXX's std flags don't get defined by our cxx macro. Rather than hard-coding to c++11, just force OBJCXX to be the same as CXX unless the user specified otherwise. Github-Pull: #9169 Rebased-From: 70266e98292bf9c8f019ca4b11d681b575f71448 --- configure.ac | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b091c74b7..41b42126e 100644 --- a/configure.ac +++ b/configure.ac @@ -45,7 +45,6 @@ else CXXFLAGS_overridden=no fi AC_PROG_CXX -m4_ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX]) dnl By default, libtool for mingw refuses to link static libs into a dll for dnl fear of mixing pic/non-pic objects, and import/export complications. Since @@ -60,6 +59,15 @@ AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory]) dnl Check if -latomic is required for CHECK_ATOMIC +dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures +dnl that we get the same -std flags for both. +m4_ifdef([AC_PROG_OBJCXX],[ +if test "x${OBJCXX+set}" = "x"; then + OBJCXX="${CXX}" +fi +AC_PROG_OBJCXX +]) + dnl Libtool init checks. LT_INIT([pic-only]) From 094848baf01ae7f2ab8dbac4a625a8c956f2a760 Mon Sep 17 00:00:00 2001 From: jnewbery Date: Tue, 27 Sep 2016 13:40:16 -0400 Subject: [PATCH 27/91] log block size and weight correctly. Github-Pull: #8838 Rebased-From: 5f274a1749acfdf331bc2931e25ac80c346e5faa --- src/miner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 957585884..6cb40dae8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -168,7 +168,6 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; nLastBlockWeight = nBlockWeight; - LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOpsCost); // Create coinbase transaction. CMutableTransaction coinbaseTx; @@ -182,6 +181,9 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); pblocktemplate->vTxFees[0] = -nFees; + uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); + LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); + // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); From da5a16b11dca8f61d75f92bb08f1dd19a7800158 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Tue, 22 Nov 2016 02:50:24 +0000 Subject: [PATCH 28/91] Always drop the least preferred HB peer when adding a new one. When a BIP152 HB-mode peer is in the least preferred position and disconnects, they will not be by ForNode on the next loop. They will continue to sit in that position and prevent deactivating HB mode for peers that are still connected. There is no reason for them to stay in the list if already gone, so drop the first element unconditionally if there are too many. Fixes issue #9163. Github-Pull: #9199 Rebased-From: ca8549d2bd32f17f8b69d1edbe3f2976fba504b4 --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 191bcff4c..6ad430428 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -510,8 +510,8 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front()); if (pnodeStop) { pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); - lNodesAnnouncingHeaderAndIDs.pop_front(); } + lNodesAnnouncingHeaderAndIDs.pop_front(); } fAnnounceUsingCMPCTBLOCK = true; pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); From 99477c71c4cdb5127e0fd6e12f29507320432d9f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 18 Nov 2016 12:15:01 -0800 Subject: [PATCH 29/91] Always add default_witness_commitment with GBT client support Github-Pull: #9189 Rebased-From: ad04d1cb35b9612d36078c62213bdbb13f56d73d --- src/main.cpp | 9 +-------- src/rpc/mining.cpp | 4 +++- src/test/miner_tests.cpp | 1 + 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6ad430428..addc0f93a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3503,15 +3503,8 @@ std::vector GenerateCoinbaseCommitment(CBlock& block, const CBloc { std::vector commitment; int commitpos = GetWitnessCommitmentIndex(block); - bool fHaveWitness = false; - for (size_t t = 1; t < block.vtx.size(); t++) { - if (!block.vtx[t].wit.IsNull()) { - fHaveWitness = true; - break; - } - } std::vector ret(32, 0x00); - if (fHaveWitness && IsWitnessEnabled(pindexPrev, consensusParams)) { + if (consensusParams.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0) { if (commitpos == -1) { uint256 witnessroot = BlockWitnessMerkleRoot(block, NULL); CHash256().Write(witnessroot.begin(), 32).Write(&ret[0], 32).Finalize(witnessroot.begin()); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index e6901bc77..ba48079c0 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -683,7 +683,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("curtime", pblock->GetBlockTime())); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); - if (!pblocktemplate->vchCoinbaseCommitment.empty()) { + + const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT]; + if (!pblocktemplate->vchCoinbaseCommitment.empty() && setClientRules.find(segwit_info.name) != setClientRules.end()) { result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end()))); } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 70ba70779..f2bd082cb 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -213,6 +213,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) txCoinbase.vin[0].scriptSig = CScript(); txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce); txCoinbase.vin[0].scriptSig.push_back(chainActive.Height()); + txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this) txCoinbase.vout[0].scriptPubKey = CScript(); pblock->vtx[0] = CTransaction(txCoinbase); if (txFirst.size() == 0) From b96a8f7df23956cc4c41c414a01964c9cad54699 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Sat, 19 Nov 2016 06:55:25 -0500 Subject: [PATCH 30/91] [qa] Test getblocktemplate default_witness_commitment Github-Pull: #9189 Rebased-From: 95f4a03777ec2ad82a94a3e2890192a93ad83509 --- qa/rpc-tests/p2p-segwit.py | 70 +++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py index 7218ae83d..fddd2627b 100755 --- a/qa/rpc-tests/p2p-segwit.py +++ b/qa/rpc-tests/p2p-segwit.py @@ -182,11 +182,6 @@ class SegWitTest(BitcoinTestFramework): def setup_chain(self): initialize_chain_clean(self.options.tmpdir, 3) - def add_options(self, parser): - parser.add_option("--oldbinary", dest="oldbinary", - default=None, - help="pre-segwit bitcoind binary for upgrade testing") - def setup_network(self): self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1"])) @@ -194,12 +189,9 @@ def setup_network(self): self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1", "-acceptnonstdtxn=0"])) connect_nodes(self.nodes[0], 1) - # If an old bitcoind is given, do the upgrade-after-activation test. - self.test_upgrade = False - if (self.options.oldbinary != None): - self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1"], binary=self.options.oldbinary)) - connect_nodes(self.nodes[0], 2) - self.test_upgrade = True + # Disable segwit's bip9 parameter to simulate upgrading after activation. + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-bip9params=segwit:0:0"])) + connect_nodes(self.nodes[0], 2) ''' Helpers ''' # Build a block on top of node0's tip. @@ -1164,7 +1156,7 @@ def test_standardness_v0(self, segwit_activated): if segwit_activated: # tx and tx2 were both accepted. Don't bother trying to reclaim the # P2PKH output; just send tx's first output back to an anyone-can-spend. - sync_mempools(self.nodes) + sync_mempools([self.nodes[0], self.nodes[1]]) tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")] tx3.vout = [CTxOut(tx.vout[0].nValue-1000, CScript([OP_TRUE]))] tx3.wit.vtxinwit.append(CTxInWitness()) @@ -1693,19 +1685,53 @@ def test_witness_sigops(self): def test_getblocktemplate_before_lockin(self): print("\tTesting getblocktemplate setting of segwit versionbit (before lockin)") - block_version = (self.nodes[0].getblocktemplate())['version'] - assert_equal(block_version & (1 << VB_WITNESS_BIT), 0) + # Node0 is segwit aware, node2 is not. + for node in [self.nodes[0], self.nodes[2]]: + gbt_results = node.getblocktemplate() + block_version = gbt_results['version'] + # If we're not indicating segwit support, we should not be signalling + # for segwit activation, nor should we get a witness commitment. + assert_equal(block_version & (1 << VB_WITNESS_BIT), 0) + assert('default_witness_commitment' not in gbt_results) # Workaround: # Can either change the tip, or change the mempool and wait 5 seconds # to trigger a recomputation of getblocktemplate. - self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) + txid = int(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1), 16) # Using mocktime lets us avoid sleep() + sync_mempools(self.nodes) self.nodes[0].setmocktime(int(time.time())+10) - - block_version = self.nodes[0].getblocktemplate({"rules" : ["segwit"]})['version'] - assert(block_version & (1 << VB_WITNESS_BIT) != 0) - self.nodes[0].setmocktime(0) # undo mocktime + self.nodes[2].setmocktime(int(time.time())+10) + + for node in [self.nodes[0], self.nodes[2]]: + gbt_results = node.getblocktemplate({"rules" : ["segwit"]}) + block_version = gbt_results['version'] + if node == self.nodes[2]: + # If this is a non-segwit node, we should still not get a witness + # commitment, nor a version bit signalling segwit. + assert_equal(block_version & (1 << VB_WITNESS_BIT), 0) + assert('default_witness_commitment' not in gbt_results) + else: + # For segwit-aware nodes, check the version bit and the witness + # commitment are correct. + assert(block_version & (1 << VB_WITNESS_BIT) != 0) + assert('default_witness_commitment' in gbt_results) + witness_commitment = gbt_results['default_witness_commitment'] + + # TODO: this duplicates some code from blocktools.py, would be nice + # to refactor. + # Check that default_witness_commitment is present. + block = CBlock() + witness_root = block.get_merkle_root([ser_uint256(0), ser_uint256(txid)]) + check_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(0))) + from test_framework.blocktools import WITNESS_COMMITMENT_HEADER + output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(check_commitment) + script = CScript([OP_RETURN, output_data]) + assert_equal(witness_commitment, bytes_to_hex_str(script)) + + # undo mocktime + self.nodes[0].setmocktime(0) + self.nodes[2].setmocktime(0) # Uncompressed pubkeys are no longer supported in default relay policy, # but (for now) are still valid in blocks. @@ -1945,6 +1971,7 @@ def run_test(self): # Advance to segwit being 'started' self.advance_to_segwit_started() + sync_blocks(self.nodes) self.test_getblocktemplate_before_lockin() sync_blocks(self.nodes) @@ -1987,10 +2014,7 @@ def run_test(self): self.test_signature_version_1() self.test_non_standard_witness() sync_blocks(self.nodes) - if self.test_upgrade: - self.test_upgrade_after_activation(self.nodes[2], 2) - else: - print("\tSkipping upgrade-after-activation test (use --oldbinary to enable)") + self.test_upgrade_after_activation(self.nodes[2], 2) self.test_witness_sigops() From ca1fd7521e86b016f2aa92048a13a297bab3c074 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Fri, 18 Nov 2016 19:11:08 +0000 Subject: [PATCH 31/91] Make orphan parent fetching ask for witnesses. In 0.13 orphan transactions began being treated as implicit INVs for their parents. But the resulting getdata were not getting the witness flag. This fixes issue #9182 reported by chjj and roasbeef on IRC. Github-Pull: #9188 Rebased-From: 5b0150a060208faf436c09b0ca9463407a869c72 --- src/main.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index addc0f93a..962960a15 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5586,10 +5586,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } if (!fRejectedParents) { + uint32_t nFetchFlags = GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()); BOOST_FOREACH(const CTxIn& txin, tx.vin) { - CInv inv(MSG_TX, txin.prevout.hash); - pfrom->AddInventoryKnown(inv); - if (!AlreadyHave(inv)) pfrom->AskFor(inv); + CInv _inv(MSG_TX | nFetchFlags, txin.prevout.hash); + pfrom->AddInventoryKnown(_inv); + if (!AlreadyHave(_inv)) pfrom->AskFor(_inv); } AddOrphanTx(tx, pfrom->GetId()); From 3a3bcbf775840be34b27523bba9e5ab6321b4ffb Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Tue, 1 Nov 2016 00:08:47 +0000 Subject: [PATCH 32/91] Use RelevantServices instead of node_network in AttemptToEvict. Use of node_network here is really meant to be a proxy of "likely to send us blocks in the future". RelevantServices is the right criteria now. Github-Pull: #9052 Rebased-From: d32036a47d9ccdc38628a7a75bb8b711af462e4f --- src/net.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index faa7b0028..7cb612ee9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -877,7 +877,7 @@ struct NodeEvictionCandidate int64_t nMinPingUsecTime; int64_t nLastBlockTime; int64_t nLastTXTime; - bool fNetworkNode; + bool fRelevantServices; bool fRelayTxes; bool fBloomFilter; CAddress addr; @@ -902,7 +902,7 @@ static bool CompareNodeBlockTime(const NodeEvictionCandidate &a, const NodeEvict { // There is a fall-through here because it is common for a node to have many peers which have not yet relayed a block. if (a.nLastBlockTime != b.nLastBlockTime) return a.nLastBlockTime < b.nLastBlockTime; - if (a.fNetworkNode != b.fNetworkNode) return b.fNetworkNode; + if (a.fRelevantServices != b.fRelevantServices) return b.fRelevantServices; return a.nTimeConnected > b.nTimeConnected; } @@ -936,7 +936,8 @@ static bool AttemptToEvictConnection() { if (node->fDisconnect) continue; NodeEvictionCandidate candidate = {node->id, node->nTimeConnected, node->nMinPingUsecTime, - node->nLastBlockTime, node->nLastTXTime, node->fNetworkNode, + node->nLastBlockTime, node->nLastTXTime, + (node->nServices & nRelevantServices) == nRelevantServices, node->fRelayTxes, node->pfilter != NULL, node->addr, node->nKeyedNetGroup}; vEvictionCandidates.push_back(candidate); } From 975ab1254eec5a191f22ba1d63863c00c88bdfcf Mon Sep 17 00:00:00 2001 From: randy-waterhouse Date: Thu, 6 Oct 2016 12:27:23 +1300 Subject: [PATCH 33/91] Update INSTALL landing redirection notice for build instructions. Github-Pull: #8896 Rebased-From: 2920be2a6994cfbffd93e72c6cf4c1ed19ac4339 --- INSTALL | 5 ----- INSTALL.md | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 INSTALL create mode 100644 INSTALL.md diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 07ee48427..000000000 --- a/INSTALL +++ /dev/null @@ -1,5 +0,0 @@ -Building Bitcoin - -See doc/build-*.md for instructions on building bitcoind, -the intended-for-services, no-graphical-interface, reference -implementation of Bitcoin. \ No newline at end of file diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 000000000..520a47d96 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,5 @@ +Building Bitcoin +================ + +See doc/build-*.md for instructions on building the various +elements of the Bitcoin Core reference implementation of Bitcoin. From 4a974b2837150097e20076e10edb24b65fb8e7f8 Mon Sep 17 00:00:00 2001 From: matthias Date: Mon, 17 Oct 2016 17:45:36 +0200 Subject: [PATCH 34/91] Simple Update to File 'bitcoin-qt.desktop' Github-Pull: #8908 Rebased-From: 164196b7c8aecb72dd20c8681bb24b81b18aecaa --- contrib/debian/bitcoin-qt.desktop | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop index 61e1aca6a..593d7584a 100644 --- a/contrib/debian/bitcoin-qt.desktop +++ b/contrib/debian/bitcoin-qt.desktop @@ -1,7 +1,8 @@ [Desktop Entry] Encoding=UTF-8 -Name=Bitcoin -Comment=Bitcoin P2P Cryptocurrency +Name=Bitcoin Core +Comment=Connect to the Bitcoin P2P Network +Comment[de]=Verbinde mit dem Bitcoin peer-to-peer Netzwerk Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi Exec=bitcoin-qt %u From c134d9206d2629b479f4e0071ecafd9ec517ec04 Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 17 Oct 2016 11:43:24 +0800 Subject: [PATCH 35/91] [build-aux] Boost_Base serial 27 Github-Pull: #8920 Rebased-From: 282abd8358e254d976cad05d0eb48586db276bcd --- build-aux/m4/ax_boost_base.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4 index 45d948933..650c94fa6 100644 --- a/build-aux/m4/ax_boost_base.m4 +++ b/build-aux/m4/ax_boost_base.m4 @@ -33,7 +33,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 26 +#serial 27 AC_DEFUN([AX_BOOST_BASE], [ @@ -96,7 +96,7 @@ if test "x$want_boost" = "xyes"; then libsubdirs="lib64 libx32 lib lib64" ;; ppc64|s390x|sparc64|aarch64|ppc64le) - libsubdirs="lib64 lib lib64 ppc64le" + libsubdirs="lib64 lib lib64" ;; esac From 40169dcda9f8e26090807a53b03d10ca22c6395c Mon Sep 17 00:00:00 2001 From: fanquake Date: Mon, 17 Oct 2016 11:43:59 +0800 Subject: [PATCH 36/91] Set minimum required Boost to 1.47.0 Github-Pull: #8920 Rebased-From: 6dd37237222f7102e223ece948150cb5c5087e3c --- configure.ac | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 41b42126e..e76a3c722 100644 --- a/configure.ac +++ b/configure.ac @@ -615,8 +615,11 @@ fi if test x$use_boost = xyes; then +dnl Minimum required Boost version +define(MINIMUM_REQUIRED_BOOST, 1.47.0) + dnl Check for boost libs -AX_BOOST_BASE +AX_BOOST_BASE([MINIMUM_REQUIRED_BOOST]) AX_BOOST_SYSTEM AX_BOOST_FILESYSTEM AX_BOOST_PROGRAM_OPTIONS From 12428b4d8a3dff3c32c909964536ed69f043f9d3 Mon Sep 17 00:00:00 2001 From: Steven Date: Sat, 15 Oct 2016 13:57:19 -0400 Subject: [PATCH 37/91] add software-properties-common This allows using `add-apt-repository`. Github-Pull: #8929 Rebased-From: aa9d3c9a503952589b359624bbb0da11dd7a5e3f --- doc/build-unix.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/build-unix.md b/doc/build-unix.md index 62e3e793e..d607d2a59 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -82,6 +82,7 @@ install necessary parts of boost: BerkeleyDB is required for the wallet. db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin). You can add the repository and install using the following commands: + sudo apt-get install software-properties-common sudo add-apt-repository ppa:bitcoin/bitcoin sudo apt-get update sudo apt-get install libdb4.8-dev libdb4.8++-dev From 106da691a5b935289dfecb25ee4fe2f085cee77f Mon Sep 17 00:00:00 2001 From: BtcDrak Date: Fri, 26 Aug 2016 22:35:46 +0100 Subject: [PATCH 38/91] Sync bitcoin-tx with tx version policy Github-Pull: #8932 Rebased-From: b0aea8057921f0ed2288cf07048f652c7d6d9cf3 --- src/bitcoin-tx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 8e8ac4745..b24f29553 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -164,7 +164,7 @@ static void RegisterLoad(const string& strInput) static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal) { int64_t newVersion = atoi64(cmdVal); - if (newVersion < 1 || newVersion > CTransaction::CURRENT_VERSION) + if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION) throw runtime_error("Invalid TX version requested"); tx.nVersion = (int) newVersion; From 6f86b5364345b238a812c9dffca13fe9f11a0073 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 30 Nov 2015 20:57:20 +0100 Subject: [PATCH 39/91] [Qt] make warnings label selectable Github-Pull: #8972 Rebased-From: ef0c9ee2960fda58b2fe5b0c3b4c672231b30322 --- src/qt/forms/overviewpage.ui | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index 6d792d147..4a6ee9250 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -20,7 +20,7 @@ false - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; + QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; } true @@ -28,6 +28,9 @@ 3 + + Qt::TextSelectableByMouse + From 973ca1e4912e7ad85e0d06e9490c5939232de6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Fri, 21 Oct 2016 23:42:37 +0200 Subject: [PATCH 40/91] Fix doxygen comment: the transaction is returned in txOut Github-Pull: #8993 Rebased-From: 1d8e12ba48154b2c59213e92efb50958d430a007 --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 962960a15..cf96efbe8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1591,7 +1591,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return res; } -/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ +/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) { CBlockIndex *pindexSlow = NULL; From 5bcb05d4e1304ac3582f1779a25693c0065c69e9 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 30 Oct 2016 16:58:13 +0100 Subject: [PATCH 41/91] [rpc] ParseHash: Fail when length is not 64 Github-Pull: #9042 Rebased-From: fa326193ad739d1f93da456b3fa73af0bbf9fdd1 --- src/rpc/server.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 23149baa6..102c77631 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -146,6 +146,8 @@ uint256 ParseHashV(const UniValue& v, string strName) strHex = v.get_str(); if (!IsHex(strHex)) // Note: IsHex("") is false throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); + if (64 != strHex.length()) + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length())); uint256 result; result.SetHex(strHex); return result; From f85ee01303b3d5127a31285b2682fcae2f8df64d Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Wed, 2 Nov 2016 21:59:09 +0300 Subject: [PATCH 42/91] Fix exit codes: - `--help`, `--version` etc should exit with `0` i.e. no error ("not enough args" case should still trigger an error) - error reading config file should exit with `1` Slightly refactor AppInitRPC/AppInitRawTx to return standard exit codes (EXIT_FAILURE/EXIT_SUCCESS) or CONTINUE_EXECUTION (-1) Github-Pull: #9067 Rebased-From: bd0de1386e1c7f9b875d52290de0d561c8d56bc9 --- src/bitcoin-cli.cpp | 28 +++++++++++++++++++--------- src/bitcoin-tx.cpp | 20 +++++++++++++++----- src/bitcoind.cpp | 2 +- src/qt/bitcoin.cpp | 4 ++-- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index a04101d3e..bf6f11a50 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -28,6 +28,7 @@ using namespace std; static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; +static const int CONTINUE_EXECUTION=-1; std::string HelpMessageCli() { @@ -67,7 +68,11 @@ class CConnectionFailed : public std::runtime_error }; -static bool AppInitRPC(int argc, char* argv[]) +// +// 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 AppInitRPC(int argc, char* argv[]) { // // Parameters @@ -85,31 +90,35 @@ static bool AppInitRPC(int argc, char* argv[]) } fprintf(stdout, "%s", strUsage.c_str()); - return false; + if (argc < 2) { + fprintf(stderr, "Error: too few parameters\n"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } if (!boost::filesystem::is_directory(GetDataDir(false))) { fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str()); - return false; + return EXIT_FAILURE; } try { ReadConfigFile(mapArgs, mapMultiArgs); } catch (const std::exception& e) { fprintf(stderr,"Error reading configuration file: %s\n", e.what()); - return false; + return EXIT_FAILURE; } // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause) try { SelectBaseParams(ChainNameFromCommandLine()); } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); - return false; + return EXIT_FAILURE; } if (GetBoolArg("-rpcssl", false)) { fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n"); - return false; + return EXIT_FAILURE; } - return true; + return CONTINUE_EXECUTION; } @@ -318,8 +327,9 @@ int main(int argc, char* argv[]) } try { - if(!AppInitRPC(argc, argv)) - return EXIT_FAILURE; + int ret = AppInitRPC(argc, argv); + if (ret != CONTINUE_EXECUTION) + return ret; } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInitRPC()"); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index b24f29553..384eae963 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -30,8 +30,13 @@ using namespace std; static bool fCreateBlank; static map registers; +static const int CONTINUE_EXECUTION=-1; -static bool AppInitRawTx(int argc, char* argv[]) +// +// 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 AppInitRawTx(int argc, char* argv[]) { // // Parameters @@ -89,9 +94,13 @@ static bool AppInitRawTx(int argc, char* argv[]) strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING")); fprintf(stdout, "%s", strUsage.c_str()); - return false; + if (argc < 2) { + fprintf(stderr, "Error: too few parameters\n"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } - return true; + return CONTINUE_EXECUTION; } static void RegisterSetJson(const string& key, const string& rawJson) @@ -680,8 +689,9 @@ int main(int argc, char* argv[]) SetupEnvironment(); try { - if(!AppInitRawTx(argc, argv)) - return EXIT_FAILURE; + int ret = AppInitRawTx(argc, argv); + if (ret != CONTINUE_EXECUTION) + return ret; } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInitRawTx()"); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 28bc374ac..b534caffa 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -93,7 +93,7 @@ bool AppInit(int argc, char* argv[]) } fprintf(stdout, "%s", strUsage.c_str()); - return false; + return true; } try diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 430e6dd0e..595fa4825 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -573,7 +573,7 @@ int main(int argc, char *argv[]) { HelpMessageDialog help(NULL, mapArgs.count("-version")); help.showOrPrint(); - return 1; + return 0; } /// 5. Now that settings and translations are available, ask user for data directory @@ -594,7 +594,7 @@ int main(int argc, char *argv[]) } catch (const std::exception& e) { QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); - return false; + return 1; } /// 7. Determine network (and switch to network specific options) From f27596a7ec3c625c3b0f25d66fc1bc804c250e7f Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Mon, 7 Nov 2016 21:31:38 +0300 Subject: [PATCH 43/91] Every main()/exit() should return/use one of EXIT_ codes instead of magic numbers Github-Pull: #9067 Rebased-From: 4441018d0860fce64ee74fa78da79bbb21114ca9 --- src/bitcoind.cpp | 4 ++-- src/qt/bitcoin.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index b534caffa..823b9ce58 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -127,7 +127,7 @@ bool AppInit(int argc, char* argv[]) if (fCommandLine) { fprintf(stderr, "Error: There is no RPC client functionality in bitcoind anymore. Use the bitcoin-cli utility instead.\n"); - exit(1); + exit(EXIT_FAILURE); } #ifndef WIN32 fDaemon = GetBoolArg("-daemon", false); @@ -187,5 +187,5 @@ int main(int argc, char* argv[]) // Connect bitcoind signal handlers noui_connect(); - return (AppInit(argc, argv) ? 0 : 1); + return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 595fa4825..d3d13423f 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -496,7 +496,7 @@ void BitcoinApplication::shutdownResult(int retval) void BitcoinApplication::handleRunawayException(const QString &message) { QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message); - ::exit(1); + ::exit(EXIT_FAILURE); } WId BitcoinApplication::getMainWinId() const @@ -573,13 +573,13 @@ int main(int argc, char *argv[]) { HelpMessageDialog help(NULL, mapArgs.count("-version")); help.showOrPrint(); - return 0; + return EXIT_SUCCESS; } /// 5. Now that settings and translations are available, ask user for data directory // User language is set up: pick a data directory if (!Intro::pickDataDirectory()) - return 0; + return EXIT_SUCCESS; /// 6. Determine availability of data directory and parse bitcoin.conf /// - Do not call GetDataDir(true) before this step finishes @@ -587,14 +587,14 @@ int main(int argc, char *argv[]) { QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); - return 1; + return EXIT_FAILURE; } try { ReadConfigFile(mapArgs, mapMultiArgs); } catch (const std::exception& e) { QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); - return 1; + return EXIT_FAILURE; } /// 7. Determine network (and switch to network specific options) @@ -608,7 +608,7 @@ int main(int argc, char *argv[]) SelectParams(ChainNameFromCommandLine()); } catch(std::exception &e) { QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: %1").arg(e.what())); - return 1; + return EXIT_FAILURE; } #ifdef ENABLE_WALLET // Parse URIs on command line -- this can affect Params() @@ -630,7 +630,7 @@ int main(int argc, char *argv[]) // - Do this after creating app and setting up translations, so errors are // translated properly. if (PaymentServer::ipcSendCommandLine()) - exit(0); + exit(EXIT_SUCCESS); // Start up the payment server early, too, so impatient users that click on // bitcoin: links repeatedly have their payment requests routed to this process: From 08d1c90113efb51d4fb2fcea36171181a66aea36 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 10 Nov 2016 00:53:55 +0300 Subject: [PATCH 44/91] Missed one "return false" in recent refactoring in #9067 Github-Pull: #9120 Rebased-From: 45d372f88900bda74835a20a44246746c2ac94e6 --- src/bitcoin-tx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 384eae963..c5ae33da8 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -48,7 +48,7 @@ static int AppInitRawTx(int argc, char* argv[]) SelectParams(ChainNameFromCommandLine()); } catch (const std::exception& e) { fprintf(stderr, "Error: %s\n", e.what()); - return false; + return EXIT_FAILURE; } fCreateBlank = GetBoolArg("-create", false); From 5f3a12c97c25f811083679cd3f284059cf7ea54f Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 7 Nov 2016 12:11:59 +0100 Subject: [PATCH 45/91] qt: Use correct conversion function for boost::path datadir Fixes #9089. Github-Pull: #9094 Rebased-From: e760b307f6210bee293796d606bcca87f86be200 --- src/qt/clientmodel.cpp | 3 ++- src/qt/paymentserver.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 14661b857..9530b63a2 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -6,6 +6,7 @@ #include "bantablemodel.h" #include "guiconstants.h" +#include "guiutil.h" #include "peertablemodel.h" #include "chainparams.h" @@ -186,7 +187,7 @@ QString ClientModel::formatClientStartupTime() const QString ClientModel::dataDir() const { - return QString::fromStdString(GetDataDir().string()); + return GUIUtil::boostPathToQString(GetDataDir()); } void ClientModel::updateBanlist() diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index c80aebb00..96627710e 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -80,7 +80,7 @@ static QString ipcServerName() // Append a simple hash of the datadir // Note that GetDataDir(true) returns a different path // for -testnet versus main net - QString ddir(QString::fromStdString(GetDataDir(true).string())); + QString ddir(GUIUtil::boostPathToQString(GetDataDir(true))); name.append(QString::number(qHash(ddir))); return name; From 6fe3981ac8267f9f045b0d518399d943d3147268 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Wed, 9 Nov 2016 12:45:13 -0500 Subject: [PATCH 46/91] net: don't send feefilter messages before the version handshake is complete Github-Pull: #9117 Rebased-From: 46625538d674a5aaf1bcfa7c8be8a49e5a23fa9e --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index cf96efbe8..083ea194a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6856,7 +6856,7 @@ bool SendMessages(CNode* pto) // Message: feefilter // // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay - if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && + if (!pto->fDisconnect && pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) { CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); int64_t timeNow = GetTimeMicros(); From f82c81b177dfb540c086ccccc39c030b8d9ca81f Mon Sep 17 00:00:00 2001 From: Masahiko Hyuga Date: Thu, 10 Nov 2016 18:18:52 +0900 Subject: [PATCH 47/91] fix getnettotals RPC description about timemillis. Github-Pull: #9122 Rebased-From: a79f864945d7abe05e777a942864c181311e5070 --- src/rpc/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 89035aaa8..51f9d1c33 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -344,7 +344,7 @@ UniValue getnettotals(const UniValue& params, bool fHelp) "{\n" " \"totalbytesrecv\": n, (numeric) Total bytes received\n" " \"totalbytessent\": n, (numeric) Total bytes sent\n" - " \"timemillis\": t, (numeric) Total cpu time\n" + " \"timemillis\": t, (numeric) Current UNIX time in milliseconds\n" " \"uploadtarget\":\n" " {\n" " \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n" From 3fffbf7ef0a224d10119551ed39cd3215001a46f Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Thu, 17 Nov 2016 14:41:18 +0100 Subject: [PATCH 48/91] Doxygen: Set PROJECT_NAME = "Bitcoin Core" Github-Pull: #9178 Rebased-From: fa63ee8e3eeef8379360c125eeb690a37f097da2 --- doc/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index b088c7623..a5f0aa6c7 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -28,7 +28,7 @@ DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. -PROJECT_NAME = Bitcoin +PROJECT_NAME = "Bitcoin Core" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or From 6d70a73968695ee34e15e31a79d889db6f53b734 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 18 Nov 2016 10:26:38 +0100 Subject: [PATCH 49/91] [Qt] fix coincontrol sort issue Github-Pull: #9185 Rebased-From: 76af4eb876814a916dd4f26cf71faa20bdc54f2d --- src/qt/coincontroldialog.cpp | 21 +++++++++++++++------ src/qt/coincontroldialog.h | 12 ++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 837f8ba6c..2a482baa6 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -35,6 +35,15 @@ QList CoinControlDialog::payAmounts; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); bool CoinControlDialog::fSubtractFeeFromAmount = false; +bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { + int column = treeWidget()->sortColumn(); + if (column == CoinControlDialog::COLUMN_AMOUNT_INT64 || column == CoinControlDialog::COLUMN_AMOUNT_INT64) + return data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong(); + if (column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_DATE_INT64) + return data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong(); + return QTreeWidgetItem::operator<(other); +} + CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::CoinControlDialog), @@ -708,7 +717,7 @@ void CoinControlDialog::updateView() model->listCoins(mapCoins); BOOST_FOREACH(const PAIRTYPE(QString, std::vector)& coins, mapCoins) { - QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem(); + CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); @@ -739,9 +748,9 @@ void CoinControlDialog::updateView() nSum += out.tx->vout[out.i].nValue; nChildren++; - QTreeWidgetItem *itemOutput; - if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress); - else itemOutput = new QTreeWidgetItem(ui->treeWidget); + CCoinControlWidgetItem *itemOutput; + if (treeMode) itemOutput = new CCoinControlWidgetItem(itemWalletAddress); + else itemOutput = new CCoinControlWidgetItem(ui->treeWidget); itemOutput->setFlags(flgCheckbox); itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked); @@ -779,11 +788,11 @@ void CoinControlDialog::updateView() // amount itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue)); - itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly + itemOutput->setData(COLUMN_AMOUNT_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly // date itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); - itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " ")); + itemOutput->setData(COLUMN_DATE_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->GetTxTime())); // confirmations itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " ")); diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 1a467eb2f..6229d21da 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -28,6 +28,17 @@ namespace Ui { #define ASYMP_UTF8 "\xE2\x89\x88" +class CCoinControlWidgetItem : public QTreeWidgetItem +{ +public: + CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {} + CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {} + CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {} + + bool operator<(const QTreeWidgetItem &other) const; +}; + + class CoinControlDialog : public QDialog { Q_OBJECT @@ -79,6 +90,7 @@ class CoinControlDialog : public QDialog COLUMN_PRIORITY_INT64, COLUMN_DATE_INT64 }; + friend class CCoinControlWidgetItem; // some columns have a hidden column containing the value used for sorting int getMappedColumn(int column, bool fVisibleColumn = true) From ff423cc6b0323854b93810fa7a9a479a746f6d5d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 18 Nov 2016 14:33:34 +0100 Subject: [PATCH 50/91] [Qt] Clean up and fix coincontrol tree widget handling - Do sorting for date, amount and confirmations column as longlong, not unsigned longlong. - Use `UserRole` to store our own data. This makes it treated as ancillary data prevents it from being displayed. - Get rid of `getMappedColumn` `strPad` - these are no longer necessary. - Get rid of hidden `_INT64` columns. - Start enumeration from 0 (otherwise values are undefined). Github-Pull: #9185 Rebased-From: 4231032bfcb9728f0f629b3d67884ba9de63e4ff --- src/qt/coincontroldialog.cpp | 39 +++++++++++------------------------- src/qt/coincontroldialog.h | 31 +--------------------------- 2 files changed, 13 insertions(+), 57 deletions(-) diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 2a482baa6..81cd098bf 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -37,10 +37,8 @@ bool CoinControlDialog::fSubtractFeeFromAmount = false; bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { int column = treeWidget()->sortColumn(); - if (column == CoinControlDialog::COLUMN_AMOUNT_INT64 || column == CoinControlDialog::COLUMN_AMOUNT_INT64) - return data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_AMOUNT_INT64, Qt::DisplayRole).toULongLong(); - if (column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_DATE_INT64) - return data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong() < other.data(CoinControlDialog::COLUMN_DATE_INT64, Qt::DisplayRole).toULongLong(); + if (column == CoinControlDialog::COLUMN_AMOUNT || column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_CONFIRMATIONS) + return data(column, Qt::UserRole).toLongLong() < other.data(column, Qt::UserRole).toLongLong(); return QTreeWidgetItem::operator<(other); } @@ -141,12 +139,9 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100); ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it - ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it - ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it - ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it // default view is sorted by amount desc - sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder); + sortView(COLUMN_AMOUNT, Qt::DescendingOrder); // restore list mode and sortorder as a convenience feature QSettings settings; @@ -178,15 +173,6 @@ void CoinControlDialog::setModel(WalletModel *model) } } -// helper function str_pad -QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding) -{ - while (s.length() < nPadLength) - s = sPadding + s; - - return s; -} - // ok button void CoinControlDialog::buttonBoxClicked(QAbstractButton* button) { @@ -358,7 +344,7 @@ void CoinControlDialog::sortView(int column, Qt::SortOrder order) sortColumn = column; sortOrder = order; ui->treeWidget->sortItems(column, order); - ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder); + ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); } // treeview: clicked on header @@ -366,12 +352,10 @@ void CoinControlDialog::headerSectionClicked(int logicalIndex) { if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing { - ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder); + ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); } else { - logicalIndex = getMappedColumn(logicalIndex, false); - if (sortColumn == logicalIndex) sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder); else @@ -788,19 +772,20 @@ void CoinControlDialog::updateView() // amount itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue)); - itemOutput->setData(COLUMN_AMOUNT_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly + itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly // date itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); - itemOutput->setData(COLUMN_DATE_INT64, Qt::DisplayRole, QVariant((qlonglong)out.tx->GetTxTime())); + itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.tx->GetTxTime())); // confirmations - itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " ")); + itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth)); + itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.nDepth)); // priority double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth+1); // 78 = 2 * 34 + 10 itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority)); - itemOutput->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPriority), 20, " ")); + itemOutput->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong)dPriority)); dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth+1); nInputSum += nInputSize; @@ -831,9 +816,9 @@ void CoinControlDialog::updateView() dPrioritySum = dPrioritySum / (nInputSum + 78); itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); - itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " ")); + itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)nSum)); itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority)); - itemWalletAddress->setText(COLUMN_PRIORITY_INT64, strPad(QString::number((int64_t)dPrioritySum), 20, " ")); + itemWalletAddress->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong)dPrioritySum)); } } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 6229d21da..785079b1a 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -71,13 +71,12 @@ class CoinControlDialog : public QDialog const PlatformStyle *platformStyle; - QString strPad(QString, int, QString); void sortView(int, Qt::SortOrder); void updateView(); enum { - COLUMN_CHECKBOX, + COLUMN_CHECKBOX = 0, COLUMN_AMOUNT, COLUMN_LABEL, COLUMN_ADDRESS, @@ -86,37 +85,9 @@ class CoinControlDialog : public QDialog COLUMN_PRIORITY, COLUMN_TXHASH, COLUMN_VOUT_INDEX, - COLUMN_AMOUNT_INT64, - COLUMN_PRIORITY_INT64, - COLUMN_DATE_INT64 }; friend class CCoinControlWidgetItem; - // some columns have a hidden column containing the value used for sorting - int getMappedColumn(int column, bool fVisibleColumn = true) - { - if (fVisibleColumn) - { - if (column == COLUMN_AMOUNT_INT64) - return COLUMN_AMOUNT; - else if (column == COLUMN_PRIORITY_INT64) - return COLUMN_PRIORITY; - else if (column == COLUMN_DATE_INT64) - return COLUMN_DATE; - } - else - { - if (column == COLUMN_AMOUNT) - return COLUMN_AMOUNT_INT64; - else if (column == COLUMN_PRIORITY) - return COLUMN_PRIORITY_INT64; - else if (column == COLUMN_DATE) - return COLUMN_DATE_INT64; - } - - return column; - } - private Q_SLOTS: void showMenu(const QPoint &); void copyAmount(); From dc46b10a087921343bb5a05d08393ece061d6303 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 18 Nov 2016 15:47:20 +0100 Subject: [PATCH 51/91] qt: Plug many memory leaks None of these are very serious, and are leaks in objects that are created at most one time. In most cases this means properly using the QObject parent hierarchy, except for BanTablePriv/PeerTablePriv which are not QObject, so use a std::unique_ptr instead. Github-Pull: #9190 Rebased-From: 47db07537746940ee7dd0739a8c73e328837813f --- src/qt/addressbookpage.cpp | 2 +- src/qt/bantablemodel.cpp | 7 ++++++- src/qt/bantablemodel.h | 3 ++- src/qt/bitcoingui.cpp | 2 +- src/qt/coincontroldialog.cpp | 2 +- src/qt/guiutil.cpp | 3 ++- src/qt/guiutil.h | 2 +- src/qt/overviewpage.cpp | 11 +++++------ src/qt/overviewpage.h | 3 ++- src/qt/peertablemodel.cpp | 9 +++++++-- src/qt/peertablemodel.h | 3 ++- src/qt/receivecoinsdialog.cpp | 5 +++-- src/qt/receiverequestdialog.cpp | 2 +- src/qt/recentrequeststablemodel.cpp | 2 +- src/qt/rpcconsole.cpp | 4 ++-- src/qt/transactionview.cpp | 6 +++--- 16 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 135f15ffa..727956c88 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -83,7 +83,7 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, deleteAction = new QAction(ui->deleteAddress->text(), this); // Build context menu - contextMenu = new QMenu(); + contextMenu = new QMenu(this); contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(editAction); diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index d95106b5a..7707ce7b6 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -86,7 +86,7 @@ BanTableModel::BanTableModel(ClientModel *parent) : clientModel(parent) { columns << tr("IP/Netmask") << tr("Banned Until"); - priv = new BanTablePriv(); + priv.reset(new BanTablePriv()); // default to unsorted priv->sortColumn = -1; @@ -94,6 +94,11 @@ BanTableModel::BanTableModel(ClientModel *parent) : refresh(); } +BanTableModel::~BanTableModel() +{ + // Intentionally left empty +} + int BanTableModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h index fe9600ac0..3c03d05c0 100644 --- a/src/qt/bantablemodel.h +++ b/src/qt/bantablemodel.h @@ -40,6 +40,7 @@ class BanTableModel : public QAbstractTableModel public: explicit BanTableModel(ClientModel *parent = 0); + ~BanTableModel(); void startAutoRefresh(); void stopAutoRefresh(); @@ -66,7 +67,7 @@ public Q_SLOTS: private: ClientModel *clientModel; QStringList columns; - BanTablePriv *priv; + std::unique_ptr priv; }; #endif // BITCOIN_QT_BANTABLEMODEL_H diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 2afefb733..169ca5008 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1147,7 +1147,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event) /** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */ void UnitDisplayStatusBarControl::createContextMenu() { - menu = new QMenu(); + menu = new QMenu(this); Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) { QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 81cd098bf..866d3872c 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -59,7 +59,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this // context menu - contextMenu = new QMenu(); + contextMenu = new QMenu(this); contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyAmountAction); diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 947a4c682..dec3e56ec 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -591,7 +591,8 @@ void TableViewLastColumnResizingFixer::on_geometriesChanged() * Initializes all internal variables and prepares the * the resize modes of the last 2 columns of the table and */ -TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth) : +TableViewLastColumnResizingFixer::TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent) : + QObject(parent), tableView(table), lastColumnMinimumWidth(lastColMinimumWidth), allColumnsMinimumWidth(allColsMinimumWidth) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 9267e0a6c..83cd6b5d4 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -150,7 +150,7 @@ namespace GUIUtil Q_OBJECT public: - TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth); + TableViewLastColumnResizingFixer(QTableView* table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent); void stretchColumnWidth(int column); private: diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 6a0404cbf..a010f0102 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -25,8 +25,8 @@ class TxViewDelegate : public QAbstractItemDelegate { Q_OBJECT public: - TxViewDelegate(const PlatformStyle *platformStyle): - QAbstractItemDelegate(), unit(BitcoinUnits::BTC), + TxViewDelegate(const PlatformStyle *platformStyle, QObject *parent=nullptr): + QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC), platformStyle(platformStyle) { @@ -119,8 +119,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) currentWatchOnlyBalance(-1), currentWatchUnconfBalance(-1), currentWatchImmatureBalance(-1), - txdelegate(new TxViewDelegate(platformStyle)), - filter(0) + txdelegate(new TxViewDelegate(platformStyle, this)) { ui->setupUi(this); @@ -213,7 +212,7 @@ void OverviewPage::setWalletModel(WalletModel *model) if(model && model->getOptionsModel()) { // Set up transaction list - filter = new TransactionFilterProxy(); + filter.reset(new TransactionFilterProxy()); filter->setSourceModel(model->getTransactionTableModel()); filter->setLimit(NUM_ITEMS); filter->setDynamicSortFilter(true); @@ -221,7 +220,7 @@ void OverviewPage::setWalletModel(WalletModel *model) filter->setShowInactive(false); filter->sort(TransactionTableModel::Date, Qt::DescendingOrder); - ui->listTransactions->setModel(filter); + ui->listTransactions->setModel(filter.get()); ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); // Keep up to date with wallet diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 911443c76..23746a6b4 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -8,6 +8,7 @@ #include "amount.h" #include +#include class ClientModel; class TransactionFilterProxy; @@ -55,7 +56,7 @@ public Q_SLOTS: CAmount currentWatchImmatureBalance; TxViewDelegate *txdelegate; - TransactionFilterProxy *filter; + std::unique_ptr filter; private Q_SLOTS: void updateDisplayUnit(); diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 84ad0052f..3829696e0 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -115,12 +115,12 @@ PeerTableModel::PeerTableModel(ClientModel *parent) : timer(0) { columns << tr("Node/Service") << tr("User Agent") << tr("Ping Time"); - priv = new PeerTablePriv(); + priv.reset(new PeerTablePriv()); // default to unsorted priv->sortColumn = -1; // set up timer for auto refresh - timer = new QTimer(); + timer = new QTimer(this); connect(timer, SIGNAL(timeout()), SLOT(refresh())); timer->setInterval(MODEL_UPDATE_DELAY); @@ -128,6 +128,11 @@ PeerTableModel::PeerTableModel(ClientModel *parent) : refresh(); } +PeerTableModel::~PeerTableModel() +{ + // Intentionally left empty +} + void PeerTableModel::startAutoRefresh() { timer->start(); diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index a2aaaa5d2..8227b5ec7 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -46,6 +46,7 @@ class PeerTableModel : public QAbstractTableModel public: explicit PeerTableModel(ClientModel *parent = 0); + ~PeerTableModel(); const CNodeCombinedStats *getNodeStats(int idx); int getRowByNodeId(NodeId nodeid); void startAutoRefresh(); @@ -74,7 +75,7 @@ public Q_SLOTS: private: ClientModel *clientModel; QStringList columns; - PeerTablePriv *priv; + std::unique_ptr priv; QTimer *timer; }; diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index 0b355837a..752a05a40 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -25,6 +25,7 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::ReceiveCoinsDialog), + columnResizingFixer(0), model(0), platformStyle(platformStyle) { @@ -48,7 +49,7 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidg QAction *copyAmountAction = new QAction(tr("Copy amount"), this); // context menu - contextMenu = new QMenu(); + contextMenu = new QMenu(this); contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyMessageAction); contextMenu->addAction(copyAmountAction); @@ -88,7 +89,7 @@ void ReceiveCoinsDialog::setModel(WalletModel *model) SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(recentRequestsView_selectionChanged(QItemSelection, QItemSelection))); // Last 2 columns are set by the columnResizingFixer, when the table geometry is ready. - columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH); + columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this); } } diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index b13ea3df7..04cc2003c 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -32,7 +32,7 @@ QRImageWidget::QRImageWidget(QWidget *parent): QLabel(parent), contextMenu(0) { - contextMenu = new QMenu(); + contextMenu = new QMenu(this); QAction *saveImageAction = new QAction(tr("&Save Image..."), this); connect(saveImageAction, SIGNAL(triggered()), this, SLOT(saveImage())); contextMenu->addAction(saveImageAction); diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index 2335d6b28..35d37bb22 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -14,7 +14,7 @@ #include RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) : - walletModel(parent) + QAbstractTableModel(parent), walletModel(parent) { Q_UNUSED(wallet); nReceiveRequestsMaxId = 0; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 650ff8b00..751ce552d 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -389,7 +389,7 @@ void RPCConsole::setClientModel(ClientModel *model) QAction* banAction365d = new QAction(tr("Ban Node for") + " " + tr("1 &year"), this); // create peer table context menu - peersTableContextMenu = new QMenu(); + peersTableContextMenu = new QMenu(this); peersTableContextMenu->addAction(disconnectAction); peersTableContextMenu->addAction(banAction1h); peersTableContextMenu->addAction(banAction24h); @@ -435,7 +435,7 @@ void RPCConsole::setClientModel(ClientModel *model) QAction* unbanAction = new QAction(tr("&Unban Node"), this); // create ban table context menu - banTableContextMenu = new QMenu(); + banTableContextMenu = new QMenu(this); banTableContextMenu->addAction(unbanAction); // ban table context menu signals diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 48cf94050..79af4a1f9 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -37,7 +37,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) : QWidget(parent), model(0), transactionProxyModel(0), - transactionView(0), abandonAction(0) + transactionView(0), abandonAction(0), columnResizingFixer(0) { // Build filter row setContentsMargins(0,0,0,0); @@ -147,7 +147,7 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa QAction *editLabelAction = new QAction(tr("Edit label"), this); QAction *showDetailsAction = new QAction(tr("Show transaction details"), this); - contextMenu = new QMenu(); + contextMenu = new QMenu(this); contextMenu->addAction(copyAddressAction); contextMenu->addAction(copyLabelAction); contextMenu->addAction(copyAmountAction); @@ -212,7 +212,7 @@ void TransactionView::setModel(WalletModel *model) transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH); - columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH); + columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH, this); if (model->getOptionsModel()) { From c12f4e93b9be01ba2d6e96f0a851562549049686 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 18 Nov 2016 16:35:14 +0100 Subject: [PATCH 52/91] qt: Prevent thread/memory leak on exiting RPCConsole Make ownership of the QThread object clear, so that the RPCConsole can wait for the executor thread to quit before shutdown is called. This increases overall thread safety, and prevents some objects from leaking on exit. Github-Pull: #9190 Rebased-From: 693384eedb1ac7f449e226edd53e2cb52a86e279 --- src/qt/bitcoin.cpp | 8 +++++--- src/qt/bitcoingui.cpp | 6 ++++++ src/qt/rpcconsole.cpp | 24 ++++++++++++++---------- src/qt/rpcconsole.h | 2 ++ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d3d13423f..ca017b2f7 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -409,6 +409,11 @@ void BitcoinApplication::requestInitialize() void BitcoinApplication::requestShutdown() { + // Show a simple window indicating shutdown status + // Do this first as some of the steps may take some time below, + // for example the RPC console may still be executing a command. + ShutdownWindow::showShutdownWindow(window); + qDebug() << __func__ << ": Requesting shutdown"; startThread(); window->hide(); @@ -423,9 +428,6 @@ void BitcoinApplication::requestShutdown() delete clientModel; clientModel = 0; - // Show a simple window indicating shutdown status - ShutdownWindow::showShutdownWindow(window); - // Request shutdown from core thread Q_EMIT requestedShutdown(); } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 169ca5008..1a5d27f6e 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -496,6 +496,12 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) // Disable context menu on tray icon trayIconMenu->clear(); } + // Propagate cleared model to child objects + rpcConsole->setClientModel(nullptr); +#ifdef ENABLE_WALLET + walletFrame->setClientModel(nullptr); +#endif // ENABLE_WALLET + unitDisplayControl->setOptionsModel(nullptr); } } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 751ce552d..167a3474c 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -288,7 +288,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : // based timer interface RPCSetTimerInterfaceIfUnset(rpcTimerInterface); - startExecutor(); setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS); ui->detailWidget->hide(); @@ -302,7 +301,6 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) : RPCConsole::~RPCConsole() { GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); - Q_EMIT stopExecutor(); RPCUnsetTimerInterface(rpcTimerInterface); delete rpcTimerInterface; delete ui; @@ -466,6 +464,14 @@ void RPCConsole::setClientModel(ClientModel *model) autoCompleter = new QCompleter(wordList, this); ui->lineEdit->setCompleter(autoCompleter); autoCompleter->popup()->installEventFilter(this); + // Start thread to execute RPC commands. + startExecutor(); + } + if (!model) { + // Client model is being set to 0, this means shutdown() is about to be called. + // Make sure we clean up the executor thread + Q_EMIT stopExecutor(); + thread.wait(); } } @@ -646,9 +652,8 @@ void RPCConsole::browseHistory(int offset) void RPCConsole::startExecutor() { - QThread *thread = new QThread; RPCExecutor *executor = new RPCExecutor(); - executor->moveToThread(thread); + executor->moveToThread(&thread); // Replies from executor object must go to this object connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString))); @@ -656,16 +661,15 @@ void RPCConsole::startExecutor() connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString))); // On stopExecutor signal - // - queue executor for deletion (in execution thread) // - quit the Qt event loop in the execution thread - connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater())); - connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit())); - // Queue the thread for deletion (in this thread) when it is finished - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + connect(this, SIGNAL(stopExecutor()), &thread, SLOT(quit())); + // - queue executor for deletion (in execution thread) + connect(&thread, SIGNAL(finished()), executor, SLOT(deleteLater()), Qt::DirectConnection); + connect(&thread, SIGNAL(finished()), this, SLOT(test()), Qt::DirectConnection); // Default implementation of QThread::run() simply spins up an event loop in the thread, // which is what we want. - thread->start(); + thread.start(); } void RPCConsole::on_tabWidget_currentChanged(int index) diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 28affa954..c1efa95f8 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -12,6 +12,7 @@ #include #include +#include class ClientModel; class PlatformStyle; @@ -140,6 +141,7 @@ public Q_SLOTS: QMenu *banTableContextMenu; int consoleFontSize; QCompleter *autoCompleter; + QThread thread; }; #endif // BITCOIN_QT_RPCCONSOLE_H From e4bea4fb84dceab44f8a8de4f8b974ba8bb98529 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 19 Nov 2016 11:08:19 +0100 Subject: [PATCH 53/91] qt: Avoid splash-screen related memory leak Make splash screen queue its own deletion when it receives the finished command, instead of relying on WA_DeleteOnClose which doesn't work under these circumstances. Github-Pull: #9190 Rebased-From: e4f126a7ba66e7317718c30276dff6db92dc1986 --- src/qt/bitcoin.cpp | 5 ++--- src/qt/splashscreen.cpp | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index ca017b2f7..d708f4b11 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -365,9 +365,8 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { SplashScreen *splash = new SplashScreen(0, networkStyle); - // We don't hold a direct pointer to the splash screen after creation, so use - // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually. - splash->setAttribute(Qt::WA_DeleteOnClose); + // We don't hold a direct pointer to the splash screen after creation, but the splash + // screen will take care of deleting itself when slotFinish happens. splash->show(); connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*))); connect(this, SIGNAL(requestedShutdown()), splash, SLOT(close())); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index e36d86fdd..68e9ffeb9 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -147,6 +147,7 @@ void SplashScreen::slotFinish(QWidget *mainWin) if (isMinimized()) showNormal(); hide(); + deleteLater(); // No more need for this } static void InitMessage(SplashScreen *splash, const std::string &message) From e5ad693f91632219407b15137b8863223919849b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 19 Nov 2016 14:28:55 +0100 Subject: [PATCH 54/91] qt: Avoid shutdownwindow-related memory leak Store a reference to the shutdown window on BitcoinApplication, so that it will be deleted when exiting the main loop. Github-Pull: #9190 Rebased-From: 5204598f8d07d7432d91e9b8781806d2f3d16415 --- src/qt/bitcoin.cpp | 3 ++- src/qt/utilitydialog.cpp | 8 +++----- src/qt/utilitydialog.h | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d708f4b11..dbf372b12 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -245,6 +245,7 @@ public Q_SLOTS: #endif int returnValue; const PlatformStyle *platformStyle; + std::unique_ptr shutdownWindow; void startThread(); }; @@ -411,7 +412,7 @@ void BitcoinApplication::requestShutdown() // Show a simple window indicating shutdown status // Do this first as some of the steps may take some time below, // for example the RPC console may still be executing a command. - ShutdownWindow::showShutdownWindow(window); + shutdownWindow.reset(ShutdownWindow::showShutdownWindow(window)); qDebug() << __func__ << ": Requesting shutdown"; startThread(); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 947bcdb15..4ec022881 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -171,22 +171,20 @@ ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f): setLayout(layout); } -void ShutdownWindow::showShutdownWindow(BitcoinGUI *window) +QWidget *ShutdownWindow::showShutdownWindow(BitcoinGUI *window) { if (!window) - return; + return nullptr; // Show a simple window indicating shutdown status QWidget *shutdownWindow = new ShutdownWindow(); - // We don't hold a direct pointer to the shutdown window after creation, so use - // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually. - shutdownWindow->setAttribute(Qt::WA_DeleteOnClose); shutdownWindow->setWindowTitle(window->windowTitle()); // Center shutdown window at where main window was const QPoint global = window->mapToGlobal(window->rect().center()); shutdownWindow->move(global.x() - shutdownWindow->width() / 2, global.y() - shutdownWindow->height() / 2); shutdownWindow->show(); + return shutdownWindow; } void ShutdownWindow::closeEvent(QCloseEvent *event) diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 843bd7f67..b93042957 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -43,7 +43,7 @@ class ShutdownWindow : public QWidget public: ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0); - static void showShutdownWindow(BitcoinGUI *window); + static QWidget *showShutdownWindow(BitcoinGUI *window); protected: void closeEvent(QCloseEvent *event); From 6f7841c4d490de01c2e458d45ba5cd1ac8ee97d5 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sat, 19 Nov 2016 16:12:23 +0100 Subject: [PATCH 55/91] qt: Avoid OpenSSL certstore-related memory leak - Correctly manage the X509 and X509_STORE objects lifetime. Github-Pull: #9190 Rebased-From: ed998ea7a0ecf294211b06e9ef82f1548a621a1d --- src/qt/paymentserver.cpp | 43 ++++++++++++++++++++++------------------ src/qt/paymentserver.h | 5 +---- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 96627710e..1ef224b52 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -58,14 +58,19 @@ const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest" // BIP70 max payment request size in bytes (DoS protection) const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000; -X509_STORE* PaymentServer::certStore = NULL; -void PaymentServer::freeCertStore() +struct X509StoreDeleter { + void operator()(X509_STORE* b) { + X509_STORE_free(b); + } +}; + +struct X509Deleter { + void operator()(X509* b) { X509_free(b); } +}; + +namespace // Anon namespace { - if (PaymentServer::certStore != NULL) - { - X509_STORE_free(PaymentServer::certStore); - PaymentServer::certStore = NULL; - } + std::unique_ptr certStore; } // @@ -107,20 +112,15 @@ static void ReportInvalidCertificate(const QSslCertificate& cert) // void PaymentServer::LoadRootCAs(X509_STORE* _store) { - if (PaymentServer::certStore == NULL) - atexit(PaymentServer::freeCertStore); - else - freeCertStore(); - // Unit tests mostly use this, to pass in fake root CAs: if (_store) { - PaymentServer::certStore = _store; + certStore.reset(_store); return; } // Normal execution, use either -rootcertificates or system certs: - PaymentServer::certStore = X509_STORE_new(); + certStore.reset(X509_STORE_new()); // Note: use "-system-" default here so that users can pass -rootcertificates="" // and get 'I don't like X.509 certificates, don't trust anybody' behavior: @@ -167,11 +167,11 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store) QByteArray certData = cert.toDer(); const unsigned char *data = (const unsigned char *)certData.data(); - X509* x509 = d2i_X509(0, &data, certData.size()); - if (x509 && X509_STORE_add_cert(PaymentServer::certStore, x509)) + std::unique_ptr x509(d2i_X509(0, &data, certData.size())); + if (x509 && X509_STORE_add_cert(certStore.get(), x509.get())) { - // Note: X509_STORE_free will free the X509* objects when - // the PaymentServer is destroyed + // Note: X509_STORE increases the reference count to the X509 object, + // we still have to release our reference to it. ++nRootCerts; } else @@ -550,7 +550,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen recipient.paymentRequest = request; recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo()); - request.getMerchant(PaymentServer::certStore, recipient.authenticatedMerchant); + request.getMerchant(certStore.get(), recipient.authenticatedMerchant); QList > sendingTos = request.getPayTo(); QStringList addresses; @@ -807,3 +807,8 @@ bool PaymentServer::verifyAmount(const CAmount& requestAmount) } return fVerified; } + +X509_STORE* PaymentServer::getCertStore() +{ + return certStore.get(); +} diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 2d27ed078..7202e7dad 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -83,7 +83,7 @@ class PaymentServer : public QObject static void LoadRootCAs(X509_STORE* store = NULL); // Return certificate store - static X509_STORE* getCertStore() { return certStore; } + static X509_STORE* getCertStore(); // OptionsModel is used for getting proxy settings and display unit void setOptionsModel(OptionsModel *optionsModel); @@ -140,9 +140,6 @@ private Q_SLOTS: bool saveURIs; // true during startup QLocalServer* uriServer; - static X509_STORE* certStore; // Trusted root certificates - static void freeCertStore(); - QNetworkAccessManager* netManager; // Used to fetch payment requests OptionsModel *optionsModel; From 0c09d9f00e39c4b1aee0fcb091fba068845b8edd Mon Sep 17 00:00:00 2001 From: Russell Yanofsky Date: Tue, 25 Oct 2016 15:30:55 -0400 Subject: [PATCH 56/91] Send tip change notification from invalidateblock This change is needed to prevent sync_blocks timeouts in the mempool_reorg test after the sync_blocks update in the upcoming commit "[qa] Change sync_blocks to pick smarter maxheight". This change was initially suggested by Suhas Daftuar in https://github.com/bitcoin/bitcoin/pull/8680#r78209060 Github-Pull: #9196 Rebased-From: 67c6326abd1788e6f411feb4f44b69774e76aae2 --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 083ea194a..10e2fa983 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3176,6 +3176,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C InvalidChainFound(pindex); mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); return true; } From eebc699d3070c71365a0f3542e2f5f6eca3fd281 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 22 Nov 2016 09:59:50 +0100 Subject: [PATCH 57/91] bench: Fix subtle counting issue when rescaling iteration count Make sure that the count is a zero modulo the new mask before scaling, otherwise the next time until a measure triggers will take only 1/2 as long as accounted for. This caused the 'min time' to be potentially off by as much as 100%. Github-Pull: #9200 Rebased-From: e0a9cb25b0af87723d50cb8d8cffa10f1ebf7dcc --- src/bench/bench.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 227546a7a..8942da8c7 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -64,8 +64,11 @@ bool State::KeepRunning() return true; } if (elapsed*16 < maxElapsed) { - countMask = ((countMask<<1)|1) & ((1LL<<60)-1); - countMaskInv = 1./(countMask+1); + uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1); + if ((count & newCountMask)==0) { + countMask = newCountMask; + countMaskInv = 1./(countMask+1); + } } } lastTime = now; From 396c405e7b4911eea3eceecd001840ffa8c38e95 Mon Sep 17 00:00:00 2001 From: Ivo van der Sangen Date: Sun, 27 Nov 2016 12:08:39 +0100 Subject: [PATCH 58/91] Include select.h when WIN32 is not defined Github-Pull: #9224 Rebased-From: 498a1d75e75649b02caeca7b1bc9bbc19e51a566 --- src/compat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compat.h b/src/compat.h index 79a297e5e..2578d6d34 100644 --- a/src/compat.h +++ b/src/compat.h @@ -34,6 +34,7 @@ #else #include #include +#include #include #include #include From 28d0f224fda3ec375c07aaa18f786ce18f674f29 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 29 Nov 2016 17:49:08 -0800 Subject: [PATCH 59/91] Fix calculation of number of bound sockets to use Github-Pull: #9253 Rebased-From: 9e1f46821d5bb69e2cbf25738eefa7c6cb99c838 --- src/init.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index eab8de8d0..4a837018b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -854,7 +854,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } // Make sure enough file descriptors are available - int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1); + int nBind = std::max( + (mapMultiArgs.count("-bind") ? mapMultiArgs.at("-bind").size() : 0) + + (mapMultiArgs.count("-whitebind") ? mapMultiArgs.at("-whitebind").size() : 0), size_t(1)); int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); nMaxConnections = std::max(nUserMaxConnections, 0); From ff55a2d22e3d93a9bfe7999277a7bffcf7f60f9d Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Tue, 18 Oct 2016 13:47:34 +0800 Subject: [PATCH 60/91] Update gitian signing key of jl2012 Github-Pull: #8950 Rebased-From: 9b0d8efe811058928a6ed3a55c0b6d58e13b22ba --- contrib/gitian-keys/jl2012-key.pgp | 374 +++++++++++++++++++++-------- 1 file changed, 272 insertions(+), 102 deletions(-) diff --git a/contrib/gitian-keys/jl2012-key.pgp b/contrib/gitian-keys/jl2012-key.pgp index b8aad7fd8..984f555cb 100644 --- a/contrib/gitian-keys/jl2012-key.pgp +++ b/contrib/gitian-keys/jl2012-key.pgp @@ -1,105 +1,275 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -Comment: GPGTools - https://gpgtools.org +Version: SKS 1.1.5 +Comment: Hostname: pgp.mit.edu -mQINBFYhRd0BEAC+2VU+8+f9RTPLtl0C815oxaOCA9Tle13xNER8NjFrVwIuFQ64 -nO8Fbhd5KEEARuMS/lc5G6IV0QxBpDGE1sEjPQXrA6UnX8SDkNGhmoAsV07MP2Xl -glN9qqYUEoVD7ueh7Cp3A9rFjg7wcMJCPQDP6lZY4cPgYlE1C31TCrEdAsVVTQg+ -xIYWnhB92VxOJhk0N0h6xtCQ2MOtYDjYcBndQ5iK7L5jy5LI89YVRfbKtWqWZdwR -lgj2JCLeXKauXBI1qbedCJrz5e8nXcdqZt9TXSHo/XhNlqvsLiqBq4aXNU3xRkrv -fcweZ9jR9DjyQzefYFGaiCk37R4qLbaqQRm0luUizkCegIuTv44e/zig0im8yPAI -WtGnmBPSy4MpvvWiVVb+jHikdQG1T7g9kF6gEmj4kj9UseWnasiq+kkSNE67vLxb -uZDfA3QhavRMJbCNEY49/IX6urIsiCLFbe6C7JVWvJ7d5l3MAHE8Sut+ytjX7z7O -LFt7YD6loxGAdopEUZm50xs8PswKDajlzWGFXjDZdzQA1tb2CpHUtDkAInYDutR4 -qA29qtxaBswozzUYiDptGSkBqD1Nus7UAJYkwe2EjeszNPhmIAQXGWx2yWplPOJk -ZWDuhQtrDXZikl70q0ekIJ7bxkpMO8xUuhsBCS3Wn6GAtySy0XTttmItfQARAQAB -tBZqbDIwMTIgPGpsMjAxMkB4YnQuaGs+iQI3BBMBCgAhBQJWIUXdAhsBBQsJCAcD -BRUKCQgLBRYCAwEAAh4BAheAAAoJEMUkKhqzk2UXsbIQAJnXDjhEoKSILJRrKbg+ -MXP3Rhxc/ThXu5C8yhfYqKblqCaNNfEmrlercJKJVMvjY0tVTXYo8BEJmNN7nSNI -su8NheJ9vXacN3XrgkMPuFiUyKj9PGpSsM6Q8MjT0Bzd0pxodk+g0UEjyMktfu/3 -TqLsnoFPOtIjMOkr/uBzZn5d0AXIZQbAz4Xa2zBW+uR3OSXRRXCRJjCSWGIfDX0Y -i/Ea+3Be+y9bMqDa3nPULEkW7+RNuyjLr6QwPZ0/BpTTDcM6Vic2daFPO5B0+o3z -PMFmPcEd4nRHTPM9A5SaJtC8MjF/89mjhpxG3v8RqkqCdqdM2cezi/T4YD4jcynE -F36Ya3GuuewxEZci/N5ySG5gG8Y+80Wgc1e+sNtvIffHk3Wju2kOvNcBA2TBw36V -XCJXHROTA5+Cx4lUxOkQTJoYSVzx852WS6WHeLg1+XnDZvT7ciVIV0ExJQ9C1XOM -wjFMRsTWl+vflxmgCeHCIari57Jw3ij7ghRCgeqLp7FIXK5qSI4Tw2eajJpoTKPs -wlaO6kvOXtaCDH30FuVhKbPxII01Xi/A2ALtTkpA6mfnf19orQjv+HxX/iwUlpHM -UwsuhpZSQYIxIv/BOQnXDfw4TcjnHsqXZbqNzzFEjGurMTlOUX4KeTPscdOLUpnO -1FM4JIVybHHfhCH9Mpq+MIwCiQGBBBMBCABrBQJWpym9BYMJZgGAXhSAAAAAABUA -QGJsb2NraGFzaEBiaXRjb2luLm9yZzAwMDAwMDAwMDAwMDAwMDAwNWJiZWZkNGM3 -Mzk5OTE0OGRmZDQ1MjA5ZjA2MTUwMTljMTNjMGVjOWUwYmQ4MzUACgkQf6sRQmfk -+gQcZAgApPqnaIIE8Q5sruzua50RFRmmBtQys8sM95ciWYE4QaTXUnlhHl4QR4z/ -TQTRSBqXpdHQ9HBWrhFb6E0ykDEVx9zdEt0fvtlhHx1ItrZetfiA4PwidnyoDKs/ -/nt01RGreKSMDGInaQVEQxvEW+A0fwvcCdE8Mh3LcIydohfqUViB0c5zb7rUmize -+2Kt4Uth9T+ooo+UE87pHSJcxlcPOv6Dc7KeoUicD8DwWdsT7oxAMk9jj/ut4UNx -xOEp9Sa3sFN20tHMqyOZwnl22Py0y4ayJnceawpuka/bx7samg/2uUrO+dNKXObN -trebP83+8UFHOo7VGhesuawgwNjWW7kBjQRWIUbHAQwAy6re/3ur/fgNfE9yKivp -Bqmjq0eU5l3iT59hvKr7S+6GHUa+YvE9BBsawDSI4UILNQX0YGT1LRa20mC1okBX -5SIEpWzoZhybTMVMwS2ZHkUyO6VBAieUVojP3XQHFcDAiBvW7RRhJ2BU+v9DGo88 -HAYqKEB85P/i/E/a1xUfTWiiIhA8Dd/Hv6pzIG5QvN8XfrMIayLwpOV1G6KvBIJb -zyUVUvLyQySiZOyDczrAxzYq7b1qv8xwHDUzyUl6skPqbex1cFWIeiML9EY4DnZ9 -l3qb31Bhp+EHydv0esclM5XKQriSg/hsnJOLlCS45z/YhqGOCoD8QxXUJ71NhD/H -QR/AvGyTDcPr1/U1DJ0lG778wCOEe1Nad0G/8rcpHSY66RZR/Wf318S7uJt0mUw2 -JMt1BRxfbdgJaleUAqYjNQAMDb8LfPO6jhQnmf0nN99dpdzkwV/drVRcLDEnupDr -keBsokcuohzE0gbjUT4cNc0DuUsIELMTApG8KQCgzJy/ABEBAAGJA8QEGAEKAA8C -GwIFAlbi67wFCQGu8u4BqcDdIAQZAQoABgUCViFGxwAKCRDunlUgNL4k0qceC/91 -2ocEDwiu9kpBGCW0HD+VSyMVjLWMiClk+jPngvNEt63ZkYqRiy7fwnPuJrLFlaL0 -E0JLIweihC5AyPSJT1Q0LnOwbqCHn1s+9RfIodG/v6M48Ez4GffOtmYwW9KqogK7 -4FwdIx/wOIYDeh4rT7LRaWBNcIXO8J1+v/83u+Vx6TWKZTiZKQMEV8VOJWfSmTCE -6HVgUYvLCPB6DI+X4aVead1kayKOSuXlG/l94B5RHlJB/xQXZd1INyrZetTZxYzZ -CBhIWaZ/ji5vqFot0xVNYplRkbg1Mc96X+hwee8eiB/ySSWxUV/DDkA5ZzuE8n8R -EEjzqazjMNe50P7XKVg/eBE+TpgCDlqv69dqnOF326m6T3+FH/LDOHguQfB7pQKx -siviqjO3molBSyMHL39XFWyteVbgbbSaTRkpX//b7dQoFMiVhigcM78qoymBi6yX -qwpN13JoNuNJhEOwex5eEEUCVibFReUkBrYoGnWbwuOxiLORx/IbuNYOvsTGYEAJ -EMUkKhqzk2UXWScQAIvAgEpQpzuE1CWMBWcM/n4ruUrOVTeo6dYpUGN1LI0758xm -4VI47I8wPEy4pAbdPcqoaNnMcA/NpSYa3hV0svQDLqT96qKTrN71N1gNJa+5w+KN -rwev8MRpjuze9b4dn3avs4L9f0fkpzjSzezKwVb7loFSZqgKAaI0aSoOUTec9+OU -5ymgkYPEEF12ydkyMzLwyKrtEnIqgwQpjYTN/3P1x7Gkhv+E8Lz06TSga84yVy5I -5gO1Hklc3MW0J9jPJe3uALUtEh49KxCE2rdbIX7YbkxWaHHfK98Mu998IXr/4eUe -Zhf2CLC2cuuYbk1/rOcxPmeIJKa6S5PlWOf3Y2yLRO0VKcjD5pcGxiImoDVXC4VM -hztCVLddjU70c1ktSIBQBu9gkpPcECrzjYtpeAavOUgmpP/zQ8X2NGp6+5n9Wwii -tAgByNCg0s+PqcAZxup34b3ZY/t475tDlAmIOovH14Aa8g+0Ketj++9rPpmg9kGs -sGmn4mVItClaA7L9vZQQFnSxjyfICKsSxBhqded0lsinlzBfXDEh3N6fEXh81/Gg -zLUmTlkhcGaFXplYqrUIlkdO9PD4R2h5P6laLhK2dAf7oKavWHZQp02Yb5nVBiDc -KiVWKBP4nuTkWZCG5R966wpR1IOQQ3LykSd5SstcZX6iTpv4NZpCxI4CXpaCuQGN -BFYhSHABDADHaEJVygBdwU81c4YynyTOnWTZX+BR3EvRW51GcnfvjqkqgmlWNLET -JkswQ8+s0mjKGVnz4dkdr4cUbVegj/St7wzoO+m5mYIDMJf1j83Vo6lTo9FJFzbc -HrYC9RS7NkQmD7qzJz4KY/h0n5szFIC/JpYECBNzYrJQc8m2kZiSlyUQJve5/I5J -iI6QnM0x4kixNe32GITmKw9s3E2iRf6yXVlsrPouNS33lPXKtvmO1ae7R+G8Ve+D -JDv+TLxccy2iU9wuz4I3k20+rlmEwk17feDhfleh5Q+qjI4vkaNcXFa5coZE0HyW -SwAtLPSOv2vWkuFeYncXRyzg/CvKR57i9wnqMzNTMt3bHY2HezE13bHln5B/Jqr4 -ihhFQBqPG+UZlGYRfAI60PLh2yftX5xkm/POiLgEKF76/yIZI8wcPzzurAhFaZBp -8/MUv2ZJ/OUT4rdEVV+6XnrijNqVBU8mf8BML5CvjyhsU69yf1mvpiLQr34FNEcn -JekDGPIk97cAEQEAAYkCJQQYAQoADwIbDAUCVuLr0AUJAa7xWwAKCRDFJCoas5Nl -F8NMD/4hRoOKENEq940Z0iJg0TDvRvRnaIYsbneRQ3yg1DGVIQ+4RHmzQdpN9MW0 -5RTRLqJsW25ydWwh7y0O/oBRjaoDRAkMSIyOo/Fy+E9WWBmAwzeYCi91MyfetKIO -ocrXxpXXKnotAFDOgWGF8K+LlTDH/biOrd8ftgOVJWhz3X04ma7xvT2tQTqfFdbt -EivA+jFExq3No0Iq+Ctt/e0H2d9np62SeKBVdpbx9xAc2tPKKDSl+FyB7lj5CK5/ -FKhotl2bJhVXET48P6e+bFVwfRO7o48zuK5CJVbbdjhavQGhQoxfedW2dn9y7QoM -qayUuVIhULE/k+y3jsJBUT7p567nSdUGbc3uKt1sfPKYTdsFbHiTRltXmsIiv4bG -PslbXSvOQblFOXWrAE22CdKmGzhlEiFnbviZCCl0BFf4CwEVBJ3p9Lcoir1l9Aty -HIIFI3z1mmTz4F9BMbe6saNwBzO+Kh4+US5NV/hqvyz0aOLltb6KfI8WF8kOa1Cx -Djz/DTHnvMWO/dIOJuKsThfuxZZq3R1w3O36RB8XzDT/8NV86gfQwN07NWz1rdy4 -60fK36EjOJDqm/434/BDzWh8TqmnSamENxBTbICmWOj/25M26tA2S9zcPLJHTGMA -3yL3QlBtjWY2uNqr51cnZHgPKxBWzaRvcrZ+lUq5EG+F4J7q5rkBjQRWIUitAQwA -5A2AhW9DFxVsM105WEErD2NuM2rvtq7dTwArBEi2KdWkSGQvCE9xgyH8u5AEWxj8 -XXHE/rfunW0d9oF7Z9FbOuV+1HQOAj5hQQWLWHERwZ4gOAqG8ZKAbuwTlqitdiXE -PZiJYZSq0NXtngyeTx7XqzQSatfFOIQLzIiwPQXX0Tt+JB3B2SN/D2NP7rubzfS2 -Bg0ErhV20fPDl8YloEJFfj9lpF0ZJnJ5hXYP9Fl4MoPkyBkGPrJPooZ4FqUFHDiw -mttzP1BzFlwpAPGpI0NrkBdBlfFAtvhjreeB5Z4VYwt1xqoXgI+jYXAxoMl+rtkK -FdWaoT7wHwqDBeBWYXoyXA2dYIY8Ux1jeDBnREck7vaXhln6zXqMAQowE+F9OQnr -Wgf/LoOn5MYxsBDY9mPAO8urxUDE+Dq43JBXlS+jybMNZWdtkaBrIde7dw9IT8Fn -p8pG78DmgPxmRFH9QoypTqMfB+x7ZuB0fk1ud4ut33qLo78BWZoW0H++13CbSmrZ -ABEBAAGJAiUEGAEKAA8CGyAFAlbi690FCQGu8SoACgkQxSQqGrOTZRcNQBAAmeL1 -8Wr7vuvL5dySoYmWqHFvM8gRUwIGza5c3D29NYZJcPJRRkdGCV2IXEuUSOLtnjAN -kTM1TVMMnetqNR8Uryr7z3XjqYLnVwGqOPnFnlkE2zS3pG8AGG6OxxBhuEMvkwcd -1s3tWUlJYRWi1XhEjVZ5Km2pHsVxvoXeJCUVsa8nSXzqF8gOLm409NFMiKkp8QOG -heEV4yWrHkySi1fVfOdrHfBzu2lUmHGgSbmJIpLcK+cL3TjpJ+DkSNbniI13I/Eb -PO4Uai4a3QYz6sspZ7UzF/pjY5v6WpWXiVB5PP2Y5BrMUgWRlFxPYTc3KiIHUYVi -IjVtSOsVaRCHL/SYRq/qHs63XxlxKIhhilbR4OO+CvJ6N/vEpSbx69SqlxgDArZy -g3QQqerlLGpSFim9iWk3QBGWtQ96Ek6rjLLOn7b34I6bxXtfcOEo7gl0Y1TFkfOp -nsXAcRLrrXCpAhgC/vIQRTMKEcC18kj/vY144DwefzYCBhbI/rCSohAq8a/zhq2T -E+xlCYy931HWlUAGx/hms/0q+KQ712Zgk4XxXEx4RZiv3zl9Uph6c7SXxAMb8o2v -PzAxd3ShNOnng9hAl8zk5O1RZPa5u51ppkO1FsJ9zjb2Kvdg4ZEBtK8jETv9ckuq -yj9YmZZSRRQ2dujg81sLQ9CrO7WB3IGpwh+4lHQ= -=1irw +mQINBFYhRd0BEAC+2VU+8+f9RTPLtl0C815oxaOCA9Tle13xNER8NjFrVwIuFQ64nO8Fbhd5 +KEEARuMS/lc5G6IV0QxBpDGE1sEjPQXrA6UnX8SDkNGhmoAsV07MP2XlglN9qqYUEoVD7ueh +7Cp3A9rFjg7wcMJCPQDP6lZY4cPgYlE1C31TCrEdAsVVTQg+xIYWnhB92VxOJhk0N0h6xtCQ +2MOtYDjYcBndQ5iK7L5jy5LI89YVRfbKtWqWZdwRlgj2JCLeXKauXBI1qbedCJrz5e8nXcdq +Zt9TXSHo/XhNlqvsLiqBq4aXNU3xRkrvfcweZ9jR9DjyQzefYFGaiCk37R4qLbaqQRm0luUi +zkCegIuTv44e/zig0im8yPAIWtGnmBPSy4MpvvWiVVb+jHikdQG1T7g9kF6gEmj4kj9UseWn +asiq+kkSNE67vLxbuZDfA3QhavRMJbCNEY49/IX6urIsiCLFbe6C7JVWvJ7d5l3MAHE8Sut+ +ytjX7z7OLFt7YD6loxGAdopEUZm50xs8PswKDajlzWGFXjDZdzQA1tb2CpHUtDkAInYDutR4 +qA29qtxaBswozzUYiDptGSkBqD1Nus7UAJYkwe2EjeszNPhmIAQXGWx2yWplPOJkZWDuhQtr +DXZikl70q0ekIJ7bxkpMO8xUuhsBCS3Wn6GAtySy0XTttmItfQARAQABtBVKb2huc29uIExh +dSA8akBpai5oaz6JAjcEEwEKACECGwEFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AFAle9oRAA +CgkQxSQqGrOTZRck4Q//W/uBcS6LuvlZsoVYA3jmJInzkQx5DektEa0kSYysV+bJptyYrYV8 +RsQoNLJCkEh6Nk2rSvA6+dcHFwHhCQdYkTKJuUT8fQXhMF4C7G8iXPIjwSVnK0wa0c0eYtr3 +m6YPFsxfb+VTI/eQlu40HP3fWf4JN7zDXlz2IarC/GAsFlfZaXVpuSmCszr1uX+ywz4DYB6e +X0FuZk9fVYp0VERg+iAybV4+dqM4ZQ0Vu1cxLzrIPH2LdLHICxg79OMzAD1MHYnzkqajO0eI +blaZCc/QPaVv2bSi42WTeJJIISN+WrpeTlz3aoqhz7eGwKIckJAygnfVhYSCX7TWcaBTW6SB +wubLTfGJM2/T+OrXvVfeGAxLDPcFwpDDLkzv2u3cDbUbhf4i2+X8Xh/51yPRhi8EwIhJlaAR +CesE+iMHHvFV+ifdrqK81U9B9uiqN2xS9UBcXcJKmp9zYkPvYWfvT+D6QmvWmQ9p+EQLm9dg +zOZM6sZjWV6WtKsJWsaLQpqjC/iVnqbJoUb5g8S/vLJTT1KaTc0aTxs0v2jBFbld/kAu7Gfe +8cGz6ZWZfIBydjHFAYxCqPG0TYoQvy7eA01Djly0SPJH9PhYPBfznU91ZcaqWCCxXlp0PgCy +woMUiwP2kvK+HWTb4dCgbQwFNChNPkZ8QAsZuxGyZd7VxdbLPYkW1IiJAjcEEwEKACEFAldF +2iMCGwEFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQxSQqGrOTZRfnZRAAtR16Ns89cP8T +AzEvw55RtjeaeSmb0mw66KT/Bzzis7aWfvebP3Yki55MygHJNu+Bb/LDBNpYlJCjAoMCdLTc ++aDYCYZkrWOLQXWBTqa6XFLeexKX+gpKrNB505n00CWvVDVGsHJZ0Ha8CDZATIlj3e4owKVQ +jMLWY70MNwT/uc7YkSd38/EW5BkA76eE/AhHanqB4cWKGSNIiaq8OJYBiGNfb81Bz4Ly4kmW +VGgshYJPQpnMQDq713WZINT9Sn/NDfCrdNjFjHHxJjymZ7RoE5teqYOw7bnbA744VFxmYMrG +DrWfrTb1FORqltr4VHJnRpFIXv61DY4+eoTi1Zd5aH+ehpfDH1G/3UhPxbmM9wBsfsgy6dMy +N2XLmL9V/eHs4lzbTCyQwuiCCu99Vsn9VWcqsXGtv2xxsR3C9PYmvkm4Z1KqasKPTvRvZ7BD +0Bsdg2eyBq1m7HTK/gzSh4aCt8H6HbIz6MwO+POaAuHiZPOiESmLk5gG7wmE+/It/5vfEwDl +zL8+5PCCZtoRWaW7lyiezpAYjUq81SEsVsAqlrtIyvJnG+wATCdUHRN6GNtfZ1aMp0i3Jei5 +ST7LGAqVF6MiLskTbmIGW+P8at69orUmpA3vcvGUiSqW5JXXiPJUwUZxNAPxvpOh4B98tXfp +8kxmSyzcHR0a2Crouh+STPq0FmpsMjAxMiA8amwyMDEyQHhidC5oaz6JARwEEAECAAYFAldF +tGoACgkQmE8QzHcWn9Kybgf8DVmGhfIlQNvMH7YIg8hGrA/Q13C+FiHG4k2RQsd8vD25Sehj +GHNEsh26TxaF1XNC/yANipXyUkfYRkweVwRyJ/OTTivCtZQ/Ct0hJA+lDSfLEWm8pdiRGdio +McFq3Uy+KGBTbdlGaSsMbfCb6hunlGnnSC36X8yxnGwGPduZDlnKxrxey+eYgAN/ivC3bmRi +gVBAgDJXOBszmINGqg1T98MSe2ph7NxvWF9mF9JenJne/juThFMf0khnalQB7NeagX0UmS8F +/i5k5JgB/YVP4zTWhiAeetzBIfiQ4GadHyW52bNT9P6Rz9kKFA7xT7Olod+KaRr4+f8/6MCS +rgvpnokBHAQQAQoABgUCV0SRKQAKCRB0gQsBI0bJpko6CAC6g9o1t+/ZexSQVGqVGyU4w22Y ++OmLlx0XFYPi5ftZ8jjUkhnujis0i/KS1oreBzg0U92Cs3pWe05eDwVcwyTGJbGR2DPRM53/ +q2ETdzBbOPrSaOjaGRrMljPgu32kaeSRQbtPt+OIhvPuHATVEaHdDbsbyAQzCgpDnA2yvLIZ +wqFPIpX+zkn4tv4DRLOHa8+2loFMX9B0dKBDy8JrUDDt8sZ7dzoxEagUxLWgDzlQ3SkIyYZz +1Kk9RCx/TxQbDSQsGGpPyhEU3MeyCRQo8klDIxzBI8jfASnaxMdn5hdFdj0/CoEMTlHr2FVR +Z1ECKgDslJ0GwDhZ4HFbXnWcNx5aiQGBBBMBCABrBQJWpym9BYMJZgGAXhSAAAAAABUAQGJs +b2NraGFzaEBiaXRjb2luLm9yZzAwMDAwMDAwMDAwMDAwMDAwNWJiZWZkNGM3Mzk5OTE0OGRm +ZDQ1MjA5ZjA2MTUwMTljMTNjMGVjOWUwYmQ4MzUACgkQf6sRQmfk+gQcZAgApPqnaIIE8Q5s +ruzua50RFRmmBtQys8sM95ciWYE4QaTXUnlhHl4QR4z/TQTRSBqXpdHQ9HBWrhFb6E0ykDEV +x9zdEt0fvtlhHx1ItrZetfiA4PwidnyoDKs//nt01RGreKSMDGInaQVEQxvEW+A0fwvcCdE8 +Mh3LcIydohfqUViB0c5zb7rUmize+2Kt4Uth9T+ooo+UE87pHSJcxlcPOv6Dc7KeoUicD8Dw +WdsT7oxAMk9jj/ut4UNxxOEp9Sa3sFN20tHMqyOZwnl22Py0y4ayJnceawpuka/bx7samg/2 +uUrO+dNKXObNtrebP83+8UFHOo7VGhesuawgwNjWW4kCHAQQAQIABgUCV0HjEgAKCRCGD+uA +TmaTILHhD/9tumyLLIMuVH0hgBPk/S3BxvQXfzgMt8xYyKw3kmGkJpble9RGYWTcT+D9Dagp +ISzGlxo9hh+I8fArryQjDuiLN3OMxDmN5ctatbVTSQyXPHOLZj6y5X8mA5gKfZb1EvcZpwoS +3sUdpb31oCrmxtRVfYv7G1PaBYGf/XILu8mwu62VimhYlK/RrNZHNeFb4mJiLFviVFtAN98s +uT3lFT+BA/RsLUO+ogNcJEPQ/2Hhg93qUuKssdHKC8q5hLozTLOxepG5JjrKUS8PIXjicsnv +ui54VPkrh+8Lez7ezh1n3SXIWySN4H2Z3uFNTkgheLA7F0NhwVKPl9TDsEaaJROrbRFVc6aE +l6IQ8Z+8Uw6IifDKg9FrKlPoL9+vBrjjK9mE6E1CdLE9kttK7dHRbtCIx7TaiWIKwq6ihmOT +Eo1Ht2aq6Jg2KMCTJMQQN0vFtgUrAJMzE+hb0q2nl8VUWe44z+WuN4JX9f7sVXn4Vw6q4hfJ +7J4hgv5SRNlGRjHZzyaJfP95VnDIzKq0V3+fRGziIvA4r3TVcIVF2bvKK7H66zdOczhB141k +UGNuDsIqTaY84uk9L7lvC2jymeqV+VZu6tgxrn6OdyYd91Oya9bdduj1oycqX21pNUySkCMj +cXbDHl8EMtQVdctS+zF/Zu1dyK3Jhu2B7VyrdlMigkFBTIkCHAQQAQIABgUCV0b2MAAKCRBr +4s7RSpkXvBw+D/wLaBkcs9iXyVMGsFZgBhJODxz9BWSHfmNOsbvLSoPHCVJtmyshDBXJSruU +dOpPST3fo0T2TLdrL7DnP3nW8BqRkAoVAExZenCpT0p1oPaQj2rV82AxVjxc6syI0e83Lmp2 +USAqM3CPEvPBUL6yzmQdajJWfNaOM9XtePSsRXPGuT3gH8rZojFH7Ay+pBbZ48du+Pfm8fJD +M0heKIBQ4bOR4YTiV9t9LxOFzzt+MtEEixoyBfA56YQUaNfvjGr0NGeGXcwbGvtj7gt+14M0 +KJI0TTZWYvWbXDkhgmY4bhLbEcH6a8v3428F56n8TAYYzqD6XvdqiC0tFZgSeEAalaiNIohy +ZY/nKvZI/0lpfVBN2ozAFGF5SVUFkLUDgUzxJTnTacTDom5iifU2jcDWccNtPMNJCoufAYEk +dTQ9g3qtLypAEwW3PY58Cvfu7a6SiBFvMprwgOHBa7JVPPOkup0Dc8F1vtzxG8gASd8dK+8h ++yE0vGP0aCDGLrOT0IgT61LsIbg+9I13EPdTLaS4TflEncoC7TNy9kyuwmiQ+ObEl/IcMj1N +uEF3zp8HNlUUURN9GTI5Xx+zHXO7G1PO+wkKCKUoHLLJxMyqCw1TFIFCcF8PnJaGSfgNgNjq +GOZzar9AJY9djlNBgp73mYc0noRgxn8qYnmPEZPrZdbZIGTqCIkCHAQSAQoABgUCVz+PLwAK +CRDAwHYTL/p2lVR8EACqVrrQOqc+5512G2TzTHw1IKasdViMVi5iKeULU3POL2bHpmGcVWmT +slPB7TNXgGj+fr/ni6P5MceyQ8kgVKfHRfH6zF+VYIAD8qkKESCbT/Wlmv+6ACKV/knl9HXs +F/Pa/b7wOqrvdF7qo/NYwzgMghu3W/FMFET1KdQ4VwvysYUe66xmXARClT4M7+Awo0yqsWHw +Rk3uTJLE/GeRX7pmQQRqX2ZbKswXvWE4ECR1IlSphN0ul59o2Lq5ruNzvptnajSMJx7HHczI +oOv8QvfsCWaVE330C7096nZJrxECo5va8JYLZaeWrc/BMnp8ozQ9GsyAtidWi6upO8mzxYNV +5NAUuvCU9KBg3DRUxgAvoY6IRyiEV1XnNt5fzoHXHQJ4wmR49UWJ/Nz9+ZT6ZO7SzgYJCASM +/6XGfvuIPb6FpGZFhsleExacgepOiVGMsZ0FYXOEVhgOCBSJkAPCqe/igDXlFCDugHOvQgFc +RPFZOFxgAicrafyFKZ8HmZKM6wxtUDtgNJg6ANUTUA74TJjs8lU2H4BRvF1bfeTdjn7LI+Nt +qmwN1PU2TGCLvrLTMWfVjoIGELkaeLhLCPAN9XSOQASzksFHKQ5AWJ38dZVtdLu08IW/AKHo +e3lzLb67C/yJKmHoKioIacOdFkDQ8dTlJ6iSk8KlAGXb+6wZcyHlKokCNwQTAQoAIQUCViFF +3QIbAQULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRDFJCoas5NlF7GyEACZ1w44RKCkiCyU +aym4PjFz90YcXP04V7uQvMoX2Kim5agmjTXxJq5Xq3CSiVTL42NLVU12KPARCZjTe50jSLLv +DYXifb12nDd164JDD7hYlMio/TxqUrDOkPDI09Ac3dKcaHZPoNFBI8jJLX7v906i7J6BTzrS +IzDpK/7gc2Z+XdAFyGUGwM+F2tswVvrkdzkl0UVwkSYwklhiHw19GIvxGvtwXvsvWzKg2t5z +1CxJFu/kTbsoy6+kMD2dPwaU0w3DOlYnNnWhTzuQdPqN8zzBZj3BHeJ0R0zzPQOUmibQvDIx +f/PZo4acRt7/EapKgnanTNnHs4v0+GA+I3MpxBd+mGtxrrnsMRGXIvzeckhuYBvGPvNFoHNX +vrDbbyH3x5N1o7tpDrzXAQNkwcN+lVwiVx0TkwOfgseJVMTpEEyaGElc8fOdlkulh3i4Nfl5 +w2b0+3IlSFdBMSUPQtVzjMIxTEbE1pfr35cZoAnhwiGq4ueycN4o+4IUQoHqi6exSFyuakiO +E8NnmoyaaEyj7MJWjupLzl7Wggx99BblYSmz8SCNNV4vwNgC7U5KQOpn539faK0I7/h8V/4s +FJaRzFMLLoaWUkGCMSL/wTkJ1w38OE3I5x7Kl2W6jc8xRIxrqzE5TlF+Cnkz7HHTi1KZztRT +OCSFcmxx34Qh/TKavjCMAokCOgQTAQoAJAIbAQULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAIZ +AQUCV72hEAAKCRDFJCoas5NlF+DZEACN2sYVaoY752e6NhbKz4IeD56/zEP1x4yaUPvcbx3g +93i2oimghVnJWvwqxESFU2MgoXsMiLeuTADOSP4iP+DeBpB8qSuesHyAdyDRFq/w1qT3pKvT +mwPNXpTha9pHQoD4+/+pBwL2pR4l6MZ5+4iXJQFQQtVOhLfq2KuGuaPro4yBiyQX2eKCim1a +dNk6qtyRkFYlOrJRPqZastfNEb2Yc0DDUFLTzjyNsRxhwUd3DdOtqO//5XMvI9q/fc5wpDSP +zNzLoSkJM4V8TTg2sS23wCh3AZB2C7wnmWK6EHGNosFL5hJ6jtW96O5KwL2b/cvIv/+v214S +AhVblvhxgJ4zSQD2UpkORfKLbyp3wwRe4PFzlJWAPM8tjnLfGU4ACa+3tubDaembPM+Ft8Id +j85+HgE0W0s/eEOBTqxkWZr7blSKeiH4u3b193aGMIGGjF2SgGAORES76er8KPlPk19XsXzK +msO84zRT9JckcM5eCYTza2o3c3ycNZN6dkEAmhs8vzDWIBzB/L4galO8M00Vtck+EIScXNKV +SgZYbFb71zcKYT8yI53ZS04/1R8VAMEblwmxiTYscrjBoCcfEKEghYgsuICXjazFyXndI+m+ +Qx+XcLbZb4ubala+GlD4YwGaAHBVCIWHpBHHSH12Z0nermU0WRB4rb0uvewxqNNXoYkCOgQT +AQoAJAIbAQULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCV0XfoQIZAQAKCRDFJCoas5NlF3+p +EACzVNajdKSJAdCgKf36HCQ0TwkYeYuR1lWwwYzw8SPwjUGukSgo4P/recCm9HyT+AKO1vBc ++vgHTPECH3trDjWFg7bcL9P/zleKqvPuKGUIYihnXZmLLsavPBuSBmu7L9OR9jgSNY18s3Rl +/uQ6boOEKIP6gKREpBTJi3EUKWx/lp9K/nlCwTGOUP3sU0vhQTM+p0XYH2lP9ZeXBhKv75dj +qXn1fF65oZMzo/mKUCsXahJZPBrobwtcI4bdDzlDlcC5pC6SngrCJIzceCgsAkfutFG/H2MR +TyArvswpuZMpdniBbgnQDLWZ2bkP6qWBak9Z/80cXlSYhO4uP+rdvKMGxiobZj3YQ4u+8zqt +GhI1P7nsOtnmEp+tVWjriVrCCrSiSWE9vYmUbxw/So+FKfdQxVJ6ER1tDYcQQf+6itykJulU +Hml3jFaXYMVK6MnsKNTUvB1dlmYnSuuNUMzcwVQCrcxgpkDt7A9sJK0+PI+3HmViiLEN6fFX +0y25mmCi7aUQdgtntiaM/BroHgA+qceKJFDQrCYVJ2ecbrAfEWo6TimRcC31V/DRKnuZAb+Y +NvaSFFO0UQojsnCtSBBfUFY6zg7vZB+hGccduqdsMCuUvrBBOYcSjY8jWOuxZgSgkqc7YqZ2 +ILPj+9Q+9H1DIwpmb6titNlijrYNItB2C1KodokEHAQRAQgABgUCV0UdVgAKCRC9ApQkIfSI +n34PH/9coCxhWRgFd7S57bMX4OeG8drxazbrq/uByZVlkejqrZU4qVgwGWe1XVZXmsoI3ISp +hNBCE1ut94+9GdRmxtXVAWS7owFLoJhXWV71vq0AsJQJAF1qIZgQqVv4JfIcaT3lPw5aSSuS +bD+NU9xVnkx7ngARNxmrCSGuXWBJXSz+Yr5mugFROJJn4mn5+Zov3Tx9OYR7ekB0ojVQfdIz +yWJefZ+pF5Owc66TpQMd5qVdHAvcO16WQSOY5YeQc0AWPPPaUc8SKzqzBMCQ+XBASrxJDmWR +MN3NagcpZDQpkvXOmgZLJagsNGxF/VTQrfg2etGnDYBelvKtNJ0IgcPCDF97mApo8/Mis7G1 ++fVZFEMSLx9zH1rudfbN3dBxy5FIm/iL1iDCA9bhXd5LV3eOqyWse7PvEE9gjoim6CVSvtWS +6vSUBGGuIpRvaF2ZhROja+n582TkGu4/9Xwp20Y+xVxoxum1uJgvooJkt71K/lFOLa/GmcR+ +fsLX0wsutyRZFQvGpps0JAxso8u9RjmR3t4n3/dSMw916GLdxO9dI4uo07ComVjZyT9mx5Vw +SngFFUJCLaMEKNYpKYGsL5pvQkr/aEFsK+PwYoBik+dSI7KAHeIhy8n+OrOUKAts688eULpH +GyFgYGDOQTWfeko3KZMfqdHIjhGRtn1Lopr7sbhDmSfF55C9FBJUo8cobMc7RCgYAKUjm7pL +L3tq8ui4ENuRdsgm8b8f8/T6t/Q7OQAdc5Zg4kYkt5Bre9BSB4expcEfqLeIwqvRPBMOYJwL +2AVwU6S+gYsBUmy5DcKU3+Eh+67+D9ITH428CIn/9bzRkwY9XfskdENZyT8ciUvtoG5u+GY/ +tCR0kej74nlX8fMmXOTsURG9G829djbIEy+vKNH+qPFAOiEyauJOuMdc0Bnb73WlvYHPUHMM +QpRu+7dZqDmnUX4QQWAFCAvZRrEy+9ZLwNDzFRptAiDgwrCge0ROwWamhYFv5b6uA54vTjdl +PgakBXGVwPklcrjRipGw52rIr33x3BYzaEGX1/bQDsDMT/jMDLaRvLc2c5JmuP1qQ7M9vE6l +cb/YUeJQP/K5n52xEuo0eJ3MDfgZ+YCHYChjiMaQJ1MnTHFM85YKY4QJeLViZfsdPktW8Z5B +4YxKtZh4a887EAX+fx49GK976U/S4FhWp9d35yOg6gBvElxP6rW6lU5sJnppu+OA+jAWgjSJ +oO7PfwAn9pbg6Sy5PKpNtoRkucp515w9oaHbrJefGFEAaTXsAry0XQfqJGUkEV6wqCagZQhQ +r5dsdN4ONhVb88qY312bPDNsRKMQ8d9GiTb6tkzK+KB0Z9ROpTXQTrPuaM+YjtHJvPUoEVnI +J+60uQGNBFYhRscBDADLqt7/e6v9+A18T3IqK+kGqaOrR5TmXeJPn2G8qvtL7oYdRr5i8T0E +GxrANIjhQgs1BfRgZPUtFrbSYLWiQFflIgSlbOhmHJtMxUzBLZkeRTI7pUECJ5RWiM/ddAcV +wMCIG9btFGEnYFT6/0MajzwcBiooQHzk/+L8T9rXFR9NaKIiEDwN38e/qnMgblC83xd+swhr +IvCk5XUboq8EglvPJRVS8vJDJKJk7INzOsDHNirtvWq/zHAcNTPJSXqyQ+pt7HVwVYh6Iwv0 +RjgOdn2XepvfUGGn4QfJ2/R6xyUzlcpCuJKD+Gyck4uUJLjnP9iGoY4KgPxDFdQnvU2EP8dB +H8C8bJMNw+vX9TUMnSUbvvzAI4R7U1p3Qb/ytykdJjrpFlH9Z/fXxLu4m3SZTDYky3UFHF9t +2AlqV5QCpiM1AAwNvwt887qOFCeZ/Sc3312l3OTBX92tVFwsMSe6kOuR4GyiRy6iHMTSBuNR +Phw1zQO5SwgQsxMCkbwpAKDMnL8AEQEAAYkDxAQYAQoADwIbAgUCVuLrvAUJAa7y7gGpwN0g +BBkBCgAGBQJWIUbHAAoJEO6eVSA0viTSpx4L/3XahwQPCK72SkEYJbQcP5VLIxWMtYyIKWT6 +M+eC80S3rdmRipGLLt/Cc+4mssWVovQTQksjB6KELkDI9IlPVDQuc7BuoIefWz71F8ih0b+/ +ozjwTPgZ9862ZjBb0qqiArvgXB0jH/A4hgN6HitPstFpYE1whc7wnX6//ze75XHpNYplOJkp +AwRXxU4lZ9KZMITodWBRi8sI8HoMj5fhpV5p3WRrIo5K5eUb+X3gHlEeUkH/FBdl3Ug3Ktl6 +1NnFjNkIGEhZpn+OLm+oWi3TFU1imVGRuDUxz3pf6HB57x6IH/JJJbFRX8MOQDlnO4TyfxEQ +SPOprOMw17nQ/tcpWD94ET5OmAIOWq/r12qc4XfbqbpPf4Uf8sM4eC5B8HulArGyK+KqM7ea +iUFLIwcvf1cVbK15VuBttJpNGSlf/9vt1CgUyJWGKBwzvyqjKYGLrJerCk3Xcmg240mEQ7B7 +Hl4QRQJWJsVF5SQGtigadZvC47GIs5HH8hu41g6+xMZgQAkQxSQqGrOTZRdZJxAAi8CASlCn +O4TUJYwFZwz+fiu5Ss5VN6jp1ilQY3UsjTvnzGbhUjjsjzA8TLikBt09yqho2cxwD82lJhre +FXSy9AMupP3qopOs3vU3WA0lr7nD4o2vB6/wxGmO7N71vh2fdq+zgv1/R+SnONLN7MrBVvuW +gVJmqAoBojRpKg5RN5z345TnKaCRg8QQXXbJ2TIzMvDIqu0SciqDBCmNhM3/c/XHsaSG/4Tw +vPTpNKBrzjJXLkjmA7UeSVzcxbQn2M8l7e4AtS0SHj0rEITat1shfthuTFZocd8r3wy733wh +ev/h5R5mF/YIsLZy65huTX+s5zE+Z4gkprpLk+VY5/djbItE7RUpyMPmlwbGIiagNVcLhUyH +O0JUt12NTvRzWS1IgFAG72CSk9wQKvONi2l4Bq85SCak//NDxfY0anr7mf1bCKK0CAHI0KDS +z4+pwBnG6nfhvdlj+3jvm0OUCYg6i8fXgBryD7Qp62P772s+maD2QaywaafiZUi0KVoDsv29 +lBAWdLGPJ8gIqxLEGGp153SWyKeXMF9cMSHc3p8ReHzX8aDMtSZOWSFwZoVemViqtQiWR070 +8PhHaHk/qVouErZ0B/ugpq9YdlCnTZhvmdUGINwqJVYoE/ie5ORZkIblH3rrClHUg5BDcvKR +J3lKy1xlfqJOm/g1mkLEjgJeloKJA8QEGAEKAA8CGwIFAle9oT8FCQN9jeYBqcDdIAQZAQoA +BgUCViFGxwAKCRDunlUgNL4k0qceC/912ocEDwiu9kpBGCW0HD+VSyMVjLWMiClk+jPngvNE +t63ZkYqRiy7fwnPuJrLFlaL0E0JLIweihC5AyPSJT1Q0LnOwbqCHn1s+9RfIodG/v6M48Ez4 +GffOtmYwW9KqogK74FwdIx/wOIYDeh4rT7LRaWBNcIXO8J1+v/83u+Vx6TWKZTiZKQMEV8VO +JWfSmTCE6HVgUYvLCPB6DI+X4aVead1kayKOSuXlG/l94B5RHlJB/xQXZd1INyrZetTZxYzZ +CBhIWaZ/ji5vqFot0xVNYplRkbg1Mc96X+hwee8eiB/ySSWxUV/DDkA5ZzuE8n8REEjzqazj +MNe50P7XKVg/eBE+TpgCDlqv69dqnOF326m6T3+FH/LDOHguQfB7pQKxsiviqjO3molBSyMH +L39XFWyteVbgbbSaTRkpX//b7dQoFMiVhigcM78qoymBi6yXqwpN13JoNuNJhEOwex5eEEUC +VibFReUkBrYoGnWbwuOxiLORx/IbuNYOvsTGYEAJEMUkKhqzk2UXmJYQAJ4fOk1J7qOUuMZj +gidORGCfejuuzKWT/dPboHeUzhfvZ01yn6hM4lLO2/pVQTJ//JWcHd9pCs9YiCMdOHiAV9h4 ++drXCcwENpwZqzk56TvfRRcKkWs5h6w4EAIKpNA7dRJiEl3FVDvZ8RW7Woydrxlpe3uszqg5 +ullPREj7Rn6kPX634iyx0FWYOaVO/jSRmdM7A9U/o0/VhHoENZ3st2ophAuGvnDcBwVU2oal +o+UOMvgJxyCcqeX2yOz/Zdbcgl6yMDlmxAD4ujCqnZ0bM3ClX1BCFPj0miLg39fx4TvIpD4V +8+da8H1jGOJZ+bzn0kNeurZ7FsdvPh/QsYz1MgxI0Y6NW/WhSLtWeq5J0ik+8HhblOBVKNlQ +zoLpIay6cUicax23kQF9zjjwvadkUved4YUWG2ndmo/8iwSrjDkM2GO+YWbTm3Ciw3s0ZK3p +RyeEKmPBU+C6keMBxxy6J/6ft9b5/1ZCDfnr/9feb006snkApbuh9AH+5U03fMN6x267sxot +Pey/FYN4/LaZqJD7+24jGIZdW3XPmtETzAqncnTIiOhLu+K0KoDQ+OCXLypRMJfURQ2XT5uD +M5mregBIAWbfC+AqF+R7QTmEaa/cZxzmeiMjj6C2VqiKUtyt52VXwL2F6te+5FSxaeigCZRf +g02/go5YdwJAeU0jB4V4iQPEBBgBCgAPBQJWIUbHAhsCBQkA7U4AAakJEMUkKhqzk2UXwN0g +BBkBCgAGBQJWIUbHAAoJEO6eVSA0viTSpx4L/3XahwQPCK72SkEYJbQcP5VLIxWMtYyIKWT6 +M+eC80S3rdmRipGLLt/Cc+4mssWVovQTQksjB6KELkDI9IlPVDQuc7BuoIefWz71F8ih0b+/ +ozjwTPgZ9862ZjBb0qqiArvgXB0jH/A4hgN6HitPstFpYE1whc7wnX6//ze75XHpNYplOJkp +AwRXxU4lZ9KZMITodWBRi8sI8HoMj5fhpV5p3WRrIo5K5eUb+X3gHlEeUkH/FBdl3Ug3Ktl6 +1NnFjNkIGEhZpn+OLm+oWi3TFU1imVGRuDUxz3pf6HB57x6IH/JJJbFRX8MOQDlnO4TyfxEQ +SPOprOMw17nQ/tcpWD94ET5OmAIOWq/r12qc4XfbqbpPf4Uf8sM4eC5B8HulArGyK+KqM7ea +iUFLIwcvf1cVbK15VuBttJpNGSlf/9vt1CgUyJWGKBwzvyqjKYGLrJerCk3Xcmg240mEQ7B7 +Hl4QRQJWJsVF5SQGtigadZvC47GIs5HH8hu41g6+xMZgQGxeD/9ynUFUsAd8UnpvHN2tTzPF +eKb1MPBzVaW0IfA8IYZKhtm4S5yp/dNpt/eQfTs74LkXN57i8576m72I5g2jarVtJG2mB9bv +5RQBrOerWT1LxQA2Q8SMOsazUIMJUU63LH//mSPHOAkTVZPFew9y9voiMYA31TcJriRYDJbI +jH3GuMRAEJYA8GiY7/HdZHnmDK0SfdOMIprQJEn6G+I7MwI8qCvb2eGLfAM2Dwq/OQ7GtLIE +fbJqI/aMPhxQHc1GsberuWYnBJMuMpScWVUJufigzpO2qQgr9VjJAAdPwgh5YfURGXHoa0IE +Sy5BnbYBcdkgq9eY3SwJUx4XhlduzEu3Z6imR0tcgaM6wIIyqCwlup0jo8rNWZ+NQmdI3cqs +IPqrKn3vRXXVT50Y12EiaWbbrd34fmKWYBNHguoEj9BEW5jP1axM43MAXzsMfuLQhJsabrF0 +JWXsJRV5gZW3iNl2D0H0fTKNqBCXeLqGPsrCnmm1m2qlvKvpJClwURC56f+X5BDq5lMvL76e +2FxPDUJNjE3UxzMQjOacRztiTst7xKIhPZEHVIQyw17bkDhxspavwU6gOsFwXKEuuwjCUyA0 +pLAH+dQzVzCRCRP2ltg92gjf2PtwdbwtiMg8t15Q3Hd/hb0EV6d+xdzYLPI8KhOe/8znmK+x +4weSvG7GdRvb+rkBjQRWIUhwAQwAx2hCVcoAXcFPNXOGMp8kzp1k2V/gUdxL0VudRnJ3746p +KoJpVjSxEyZLMEPPrNJoyhlZ8+HZHa+HFG1XoI/0re8M6DvpuZmCAzCX9Y/N1aOpU6PRSRc2 +3B62AvUUuzZEJg+6syc+CmP4dJ+bMxSAvyaWBAgTc2KyUHPJtpGYkpclECb3ufyOSYiOkJzN +MeJIsTXt9hiE5isPbNxNokX+sl1ZbKz6LjUt95T1yrb5jtWnu0fhvFXvgyQ7/ky8XHMtolPc +Ls+CN5NtPq5ZhMJNe33g4X5XoeUPqoyOL5GjXFxWuXKGRNB8lksALSz0jr9r1pLhXmJ3F0cs +4Pwrykee4vcJ6jMzUzLd2x2Nh3sxNd2x5Z+Qfyaq+IoYRUAajxvlGZRmEXwCOtDy4dsn7V+c +ZJvzzoi4BChe+v8iGSPMHD887qwIRWmQafPzFL9mSfzlE+K3RFVful564ozalQVPJn/ATC+Q +r48obFOvcn9Zr6Yi0K9+BTRHJyXpAxjyJPe3ABEBAAGJAiUEGAEKAA8CGwwFAlbi69AFCQGu +8VsACgkQxSQqGrOTZRfDTA/+IUaDihDRKveNGdIiYNEw70b0Z2iGLG53kUN8oNQxlSEPuER5 +s0HaTfTFtOUU0S6ibFtucnVsIe8tDv6AUY2qA0QJDEiMjqPxcvhPVlgZgMM3mAovdTMn3rSi +DqHK18aV1yp6LQBQzoFhhfCvi5Uwx/24jq3fH7YDlSVoc919OJmu8b09rUE6nxXW7RIrwPox +RMatzaNCKvgrbf3tB9nfZ6etknigVXaW8fcQHNrTyig0pfhcge5Y+QiufxSoaLZdmyYVVxE+ +PD+nvmxVcH0Tu6OPM7iuQiVW23Y4Wr0BoUKMX3nVtnZ/cu0KDKmslLlSIVCxP5Pst47CQVE+ +6eeu50nVBm3N7irdbHzymE3bBWx4k0ZbV5rCIr+Gxj7JW10rzkG5RTl1qwBNtgnSphs4ZRIh +Z274mQgpdARX+AsBFQSd6fS3KIq9ZfQLchyCBSN89Zpk8+BfQTG3urGjcAczvioePlEuTVf4 +ar8s9Gji5bW+inyPFhfJDmtQsQ48/w0x57zFjv3SDibirE4X7sWWat0dcNzt+kQfF8w0//DV +fOoH0MDdOzVs9a3cuOtHyt+hIziQ6pv+N+PwQ81ofE6pp0mphDcQU2yApljo/9uTNurQNkvc +3DyyR0xjAN8i90JQbY1mNrjaq+dXJ2R4DysQVs2kb3K2fpVKuRBvheCe6uaJAiUEGAEKAA8C +GwwFAle9oUoFCQN9jFgACgkQxSQqGrOTZRc0yQ/9Hk0ADSWmmggcisR+ONFze/3UWww+hVdc +5qvLaTvVayeoTqsDpECoZT1gvrLMwUZ24cWxgc8Xx6QuNaFX0nql+1iaGpuyfo1sgg1q7e6y +z+d/3MvnsfB1i9g1tlRSWsbziljaqH5B5mq5hhYm5rmjJr4KbXCtyWu1XlaVOFRcUNsUipnG +jdqrmHfbY4mMDhBlCcMly8eKoWyX+hSZ2TsK5ryApK8thtvv3bANJnmaKXD+5kdrXkaW2u/s +duVlW1ad1oTDEM5y7m1LqUMtVZUHdLn+f+XGi0t8EKMW2PQ+owkkEEiQrIrArXXouhl/b4fD +kqozjE15eoBCghQBauo68/HodTGDwOBUTFgKc32g3rKkumljIzfYtsZVUk7XkvT/D9bsiHqP +R7M6m8FU+PDXRX75c3z/fp927AgZpdd6sfQygLX7JDoSZa5iY8nk2MOr8aN7vBIIiRm3k6dY +jOlpiaNVNfVYIl7XJ3k9F5Kdf6g8rNnYezphmO6+HvnEWnHYa5T7jPhFFeQwRWYK1gLSXzft +hrFrYKkLBtfUefPFOUp6/dMeRMLoXGW0TxN9pGem3Ovf2ixM9ti0BfKPjcW+GEtxgU9DloLW +oezXNdQPoD80xdYZuCV4NsTstrP5IeUkTPefnxOUWS1XiwfEDhpv1oydL0MnWDYK+jXacpVT +4mCJAiUEGAEKAA8FAlYhSHACGwwFCQDtTgAACgkQxSQqGrOTZRfcZRAAvGiCvggMlw339PE6 +coJxLV/PWIAiwj7QPtjWXm9aswHSMK5mmQ5/RgfC/11oV9QBK3t3eknEGcKhJDkw4xAB3aYd +kp35+mC6CXtRnIKXb9vyznGqd6DW0+FyDYj9/1ynuwmKnJnAzSDr7j3rpYbxGkmVBGwLfK85 +psidexuiK+1chvNHFrT4bwzSX6lB6808SQYO80vddRgjiZySs8JxziKSFv1DhsrgL/QCSlwq +QKcImQLRHvVqF8hBTUwSMbvGhmLVHCyekayh/rNtAgDf2163BYRMZfXZXxIOoNsD/bCsJzir +BmhwDY/9WhO8VDY1JcSD8V7zH4mLE6QDLllLVhyV330zsn14gaV6GC+q9NBqlEdYlofGXluj +HHAbg4V5SbWMzeJjsMUQDSLuSLMEN1GX4bHiY7amHRv4fyEtGLyDp9WaT6wn5CHoFC92GOsK +NAxTJw/kIa0J1O5cnIuS1fbymQtt9itbmSUHNhLcoE9Vg1V5yl9000bFLhKK5zv6cWQtEP8U +thTSJGHtnZ/zGC+oDvDbtyaTfa8Cj80IuGO4CBojG3HKzt/ZI4g2Gi8fnkYLgI/tx2u/c0/2 +WzAP5sEsGyiq7MvcPBV87JVnzzJvgxm4+lO1DVD/QKQd/NtrVJ8jXcuc21DE5o704rnBLawU +f4U6Tde+ZZx9WgxvAMi5AY0EViFIrQEMAOQNgIVvQxcVbDNdOVhBKw9jbjNq77au3U8AKwRI +tinVpEhkLwhPcYMh/LuQBFsY/F1xxP637p1tHfaBe2fRWzrlftR0DgI+YUEFi1hxEcGeIDgK +hvGSgG7sE5aorXYlxD2YiWGUqtDV7Z4Mnk8e16s0EmrXxTiEC8yIsD0F19E7fiQdwdkjfw9j +T+67m830tgYNBK4VdtHzw5fGJaBCRX4/ZaRdGSZyeYV2D/RZeDKD5MgZBj6yT6KGeBalBRw4 +sJrbcz9QcxZcKQDxqSNDa5AXQZXxQLb4Y63ngeWeFWMLdcaqF4CPo2FwMaDJfq7ZChXVmqE+ +8B8KgwXgVmF6MlwNnWCGPFMdY3gwZ0RHJO72l4ZZ+s16jAEKMBPhfTkJ61oH/y6Dp+TGMbAQ +2PZjwDvLq8VAxPg6uNyQV5Uvo8mzDWVnbZGgayHXu3cPSE/BZ6fKRu/A5oD8ZkRR/UKMqU6j +Hwfse2bgdH5NbneLrd96i6O/AVmaFtB/vtdwm0pq2QARAQABiQIlBBgBCgAPAhsgBQJW4uvd +BQkBrvEqAAoJEMUkKhqzk2UXDUAQAJni9fFq+77ry+XckqGJlqhxbzPIEVMCBs2uXNw9vTWG +SXDyUUZHRgldiFxLlEji7Z4wDZEzNU1TDJ3rajUfFK8q+89146mC51cBqjj5xZ5ZBNs0t6Rv +ABhujscQYbhDL5MHHdbN7VlJSWEVotV4RI1WeSptqR7Fcb6F3iQlFbGvJ0l86hfIDi5uNPTR +TIipKfEDhoXhFeMlqx5MkotX1Xznax3wc7tpVJhxoEm5iSKS3CvnC9046Sfg5EjW54iNdyPx +GzzuFGouGt0GM+rLKWe1Mxf6Y2Ob+lqVl4lQeTz9mOQazFIFkZRcT2E3NyoiB1GFYiI1bUjr +FWkQhy/0mEav6h7Ot18ZcSiIYYpW0eDjvgryejf7xKUm8evUqpcYAwK2coN0EKnq5SxqUhYp +vYlpN0ARlrUPehJOq4yyzp+29+COm8V7X3DhKO4JdGNUxZHzqZ7FwHES661wqQIYAv7yEEUz +ChHAtfJI/72NeOA8Hn82AgYWyP6wkqIQKvGv84atkxPsZQmMvd9R1pVABsf4ZrP9KvikO9dm +YJOF8VxMeEWYr985fVKYenO0l8QDG/KNrz8wMXd0oTTp54PYQJfM5OTtUWT2ubudaaZDtRbC +fc429ir3YOGRAbSvIxE7/XJLqso/WJmWUkUUNnbo4PNbC0PQqzu1gdyBqcIfuJR0iQIlBBgB +CgAPAhsgBQJXvaFaBQkDfYwqAAoJEMUkKhqzk2UXy2cP/R9HTn+6b1WuvpZ7fK4zyFSM5DF1 +86pyLe8XKEzxOs5zSaJRs3bziVdWlTTYC4f5D3TQH6NjlD9KThpOqIX2W90dfLYiRUDVzZtk +Qs0gM0U9RGYoqP08oUhdoy+Qe19y/f3yaEsUgpZ5WEj3IaOBnwvsFWQr00t8eQLRPZxc65cY +JLkHuB/S+PyQy+BATFg1JepM5Ov4oddcRAyk6eD/fnIhb5hxZGipVpSCZiCCQbrXEKbCiWP+ +LJg+N9cmRJ901tx0eEKDH4JxKxtQybhHtAV7IqrFWxHNJWDiW2gcsaSMVRi+I3f7Tq88GJdc +VGjxwzRAySVZ529ZEJydQKfa144P20NL0HrIdOiHVgJgXrL19+uyaF+7wTqV+B8z8HNl61zh +ZZpwYchKkq7X73yaOIt6o7JuUCdpYqei1a8pdNrhKyqOyqzvXlUevaRlNO0uDoUKdpLOOWm7 +cHuksxl1ZyMRr5v0e9qtfekR9st2+9RQYW+8ZbY82G9XG9ywpOpjKYcUYg9yZDxHmLaGPozU +4GCln7sIwAkG0iQfQDWF6PrzOvlAXaqEm19Z/LFsyALTHl5cAE8K0a/5qQc6hnLS9Dm/rZug +mbxazVhVszVkOzC2g6qmaJOzou2x3LFzT5PUg+VapVnFcmpFDx5mJMfJ7a1AyVDiv3zj/9zF +JuP1GY+6iQIlBBgBCgAPBQJWIUitAhsgBQkA7U4AAAoJEMUkKhqzk2UXirwP/1V1gt3j6mFK +Uzx3GE+Mb+W4crfTJY+r2yYhgUEK/Eqmp3qUgtJGv+sRJjgi5LMwTBhyHCQCSVujSBT3rKz6 +e6eVVezcPEmCSMyCV07GIQ0AlAWbYS7/ENGZx4EHlA7dJBDVYnEoLKbKmRu+v1pFcK9jPrkK +DwhRGthDm8qod4WxWay/yhiNlxcikeajI7+0ON7kfTPHeogxGD3wXMby4kosNn6QlvzKFHsu +srfr8YdBxQ5lIXPZyqNTs58oDX/1bM/SyernTZRNGauSVFy+sKiH/LSMWJsfnOT2sZ1AbpRS +khWEIPUZjEWFFjh7vxO1T5MHPq95HSPv6bj8whU+7KOrIkMuDBoceemrzcTXmBMYc181FqCx +8RAad4CX/oKDD23HKQ7bO/lJYdhIQb+QCKVWjdOS+BbjdDanS2EyGog1V6AMWcR+WhPdzO1W +mNhk8D5mrUQysjd5JrAzZ1w2iw1I3e9o02Zex/zPSAUmpa00hzN8pIZezX1I1h1mXHqpYKP1 +EvVdUEFsshVmjRNAYsKflXFWRxqQGlL0PSK6vHGlN6ZvkoS4qHRYV8zoPBivIyTcGLuRORHG +sRlAsdtxbwFYKeVqd/Yw5cocrw1C7ja1OpBFdL8kEt2kzOTAwdAebvntf0GY8TEPA4dYUFmv +Ww8nn+QC38ITGK9hVF+eVkuR +=j8C/ -----END PGP PUBLIC KEY BLOCK----- From b1e978cfd6de4e61659e019c52d9c4953b9791c1 Mon Sep 17 00:00:00 2001 From: "S. Matthew English" Date: Thu, 27 Oct 2016 12:13:03 +0200 Subject: [PATCH 61/91] instance of 'mem pool' to 'mempool' there was only one instance of 'mem pool' and not 'mempool', so I changed it to conform to the others Github-Pull: #9029 Rebased-From: 1c3ecc70c8cd6c33cf3ff4e2099c8e7d8a8ca9d2 --- src/rpc/blockchain.cpp | 2 +- src/rpc/mining.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6f97671f5..a38b3fc60 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -719,7 +719,7 @@ UniValue gettxout(const UniValue& params, bool fHelp) "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "2. n (numeric, required) vout number\n" - "3. includemempool (boolean, optional) Whether to include the mem pool\n" + "3. includemempool (boolean, optional) Whether to include the mempool\n" "\nResult:\n" "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index ba48079c0..e5eb4b8c1 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -229,7 +229,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" " \"errors\": \"...\" (string) Current errors\n" " \"networkhashps\": nnn, (numeric) The network hashes per second\n" - " \"pooledtx\": n (numeric) The size of the mem pool\n" + " \"pooledtx\": n (numeric) The size of the mempool\n" " \"testnet\": true|false (boolean) If using testnet or not\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" "}\n" From 87fbcede5ceb49fc24c3102c0f3cf81a68617ac6 Mon Sep 17 00:00:00 2001 From: matthias Date: Mon, 31 Oct 2016 01:11:46 +0100 Subject: [PATCH 62/91] Change all instance of 'GMT epoch' to 'Unix epoch' Github-Pull: #9041 Rebased-From: 7f61b49de82989dc692e7750860eb1ec4044db7a --- src/rpc/misc.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 06489566b..11befb529 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -57,7 +57,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" - " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" + " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n" " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2ad379e46..fdb7a53d3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2274,7 +2274,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp) " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n" " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n" " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n" - " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" + " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n" " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n" From 387ec9d9635580fbbedc222126c5b1a68002d543 Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Sat, 15 Oct 2016 23:45:07 +0800 Subject: [PATCH 63/91] Add script tests for FindAndDelete in pre-segwit and segwit scripts Github-Pull: #8927 Rebased-From: acf853df910339412bafb1743f42af1774f5b910 --- src/script/interpreter.cpp | 4 ++-- src/test/data/tx_invalid.json | 26 ++++++++++++++++++++++++++ src/test/data/tx_valid.json | 23 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 836cf9ee3..0e17ddc13 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -890,7 +890,7 @@ bool EvalScript(vector >& stack, const CScript& script, un // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); - // Drop the signature, since there's no way for a signature to sign itself + // Drop the signature in pre-segwit scripts but not segwit scripts if (sigversion == SIGVERSION_BASE) { scriptCode.FindAndDelete(CScript(vchSig)); } @@ -951,7 +951,7 @@ bool EvalScript(vector >& stack, const CScript& script, un // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); - // Drop the signatures, since there's no way for a signature to sign itself + // Drop the signature in pre-segwit scripts but not segwit scripts for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index f8baee057..f7d9e1847 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -314,5 +314,31 @@ [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x60 0x21 0xff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbff", 1000]], "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "P2SH,WITNESS,DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"], +["FindAndDelete tests"], +["This is a test of FindAndDelete. The first tx is a spend of normal scriptPubKey and the second tx is a spend of bare P2WSH."], +["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."], +["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> ,"], +["where the pubkey is obtained through key recovery with sig and the wrong sighash."], +["This is to show that FindAndDelete is applied only to non-segwit scripts"], +["To show that the tests are 'correctly wrong', they should pass by modifying OP_CHECKSIG under interpreter.cpp"], +["by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE)"], +["Non-segwit: wrong sighash (without FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"], +[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]], +"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012103b12a1ec8428fc74166926318c15e17408fea82dbb157575e16a8c365f546248f4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"], +["BIP143: wrong sighash (with FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"], +[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]], +"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9d7ed6e161f0e255c10bbfcca0128a9e2035c2c8da58899c54d22d3a31afdef4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"], +["This is multisig version of the FindAndDelete tests"], +["Script is 2 CHECKMULTISIGVERIFY DROP"], +["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"], +["Signature is 0 2 "], +["Should pass by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE) under OP_CHECKMULTISIG"], +["Non-segwit: wrong sighash (without FindAndDelete) = 4bc6a53e8e16ef508c19e38bba08831daba85228b0211f323d4cb0999cf2a5e8"], +[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]], +"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596015221023fd5dd42b44769c5653cbc5947ff30ab8871f240ad0c0e7432aefe84b5b4ff3421039d52178dbde360b83f19cf348deb04fa8360e1bf5634577be8e50fafc2b0e4ef4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"], +["BIP143: wrong sighash (with FindAndDelete) = 17c50ec2181ecdfdc85ca081174b248199ba81fff730794d4f69b8ec031f2dce"], +[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]], +"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601010221023cb6055f4b57a1580c5a753e19610cafaedf7e0ff377731c77837fd666eae1712102c1b1db303ac232ffa8e5e7cc2cf5f96c6e40d3e6914061204c0541cb2043a0969552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"], + ["Make diffs cleaner by leaving a comment here without comma at the end"] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 1ea70135b..2f299aa5f 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -487,5 +487,28 @@ [[["6eb98797a21c6c10aa74edf29d618be109f48a8e94c694f3701e08ca69186436", 1, "HASH160 0x14 0x9993a429037b5d912407a71c252019287b8d27a5 EQUAL", 987654321]], "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000", "P2SH,WITNESS"], +["FindAndDelete tests"], +["This is a test of FindAndDelete. The first tx is a spend of normal P2SH and the second tx is a spend of bare P2WSH."], +["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."], +["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> ,"], +["where the pubkey is obtained through key recovery with sig and correct sighash."], +["This is to show that FindAndDelete is applied only to non-segwit scripts"], +["Non-segwit: correct sighash (with FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"], +[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]], +"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0121037a3fb04bcdb09eba90f69961ba1692a3528e45e67c85b200df820212d7594d334aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"], +["BIP143: correct sighash (without FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"], +[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]], +"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"], +["This is multisig version of the FindAndDelete tests"], +["Script is 2 CHECKMULTISIGVERIFY DROP"], +["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"], +["Signature is 0 2 "], +["Non-segwit: correct sighash (with FindAndDelete) = 1d50f00ba4db2917b903b0ec5002e017343bb38876398c9510570f5dce099295"], +[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]], +"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601522102cd74a2809ffeeed0092bc124fd79836706e41f048db3f6ae9df8708cefb83a1c2102e615999372426e46fd107b76eaf007156a507584aa2cc21de9eee3bdbd26d36c4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"], +["BIP143: correct sighash (without FindAndDelete) = c1628a1e7c67f14ca0c27c06e4fdeec2e6d1a73c7a91d7c046ff83e835aebb72"], +[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]], +"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"], + ["Make diffs cleaner by leaving a comment here without comma at the end"] ] From ecd7db57672d4f2dbc85ac03e571b795b0259298 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 7 Nov 2016 23:00:54 +0100 Subject: [PATCH 64/91] [qa] test_framework: Exit when tmpdir exists Github-Pull: #9098 Rebased-From: fae19aa1da0858678874815b344de83e1ee3a1bd --- qa/rpc-tests/test_framework/test_framework.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py index 9d15d8745..bb624301c 100755 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -137,16 +137,11 @@ def main(self): success = False try: - if not os.path.isdir(self.options.tmpdir): - os.makedirs(self.options.tmpdir) + os.makedirs(self.options.tmpdir, exist_ok=False) self.setup_chain() - self.setup_network() - self.run_test() - success = True - except JSONRPCException as e: print("JSONRPC error: "+e.error['message']) traceback.print_tb(sys.exc_info()[2]) From 58eab244fb9514b74e157b5dde9060cc8f3b77a8 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 7 Nov 2016 22:33:22 +0100 Subject: [PATCH 65/91] [qa] rpc-tests: Apply random offset to portseed This helps to skip over resources, which are blocked by regtest bitcoind zombie nodes Github-Pull: #9098 Rebased-From: fab0f07dec8d6e21ab70843fdce101f1703588fd --- qa/pull-tester/rpc-tests.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index dbd6de559..887644c51 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -243,6 +243,10 @@ def __init__(self, num_tests_parallel, test_list=None, flags=None): self.test_list = test_list self.flags = flags self.num_running = 0 + # In case there is a graveyard of zombie bitcoinds, we can apply a + # pseudorandom offset to hopefully jump over them. + # (625 is PORT_RANGE/MAX_NODES) + self.portseed_offset = int(time.time() * 1000) % 625 self.jobs = [] def get_next(self): @@ -250,7 +254,7 @@ def get_next(self): # Add tests self.num_running += 1 t = self.test_list.pop(0) - port_seed = ["--portseed=%s" % len(self.test_list)] + port_seed = ["--portseed={}".format(len(self.test_list) + self.portseed_offset)] log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) self.jobs.append((t, From 3688866880decdbe9c2b551a1b701c752f8013d2 Mon Sep 17 00:00:00 2001 From: Alex Morcos Date: Tue, 29 Nov 2016 12:18:44 -0500 Subject: [PATCH 66/91] Disable fee estimates for a confirm target of 1 block Backport of #9239 without GUI changes and fixing conflicts in tests. --- src/policy/fees.cpp | 7 ++++++- src/rpc/mining.cpp | 2 ++ src/test/policyestimator_tests.cpp | 30 ++++++++++++++++++++++-------- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 7b0e8b7d0..453b4a57d 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -495,7 +495,8 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) { // Return failure if trying to analyze a target we're not tracking - if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) + // It's not possible to get reasonable estimates for confTarget of 1 + if (confTarget <= 1 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) return CFeeRate(0); double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); @@ -514,6 +515,10 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms()) return CFeeRate(0); + // It's not possible to get reasonable estimates for confTarget of 1 + if (confTarget == 1) + confTarget = 2; + double median = -1; while (median < 0 && (unsigned int)confTarget <= feeStats.GetMaxConfirms()) { median = feeStats.EstimateMedianVal(confTarget++, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index e6901bc77..a574709d9 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -791,6 +791,8 @@ UniValue estimatefee(const UniValue& params, bool fHelp) "\n" "A negative value is returned if not enough transactions and blocks\n" "have been observed to make an estimate.\n" + "-1 is always returned for nblocks == 1 as it is impossible to calculate\n" + "a fee that is high enough to get reliably included in the next block.\n" "\nExample:\n" + HelpExampleCli("estimatefee", "6") ); diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 5c902387f..fa00a1c46 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -105,19 +105,26 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // Highest feerate is 10*baseRate and gets in all blocks, // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, - // so estimateFee(1) should return 10*baseRate. + // so estimateFee(1) would return 10*baseRate but is hardcoded to return failure // Second highest feerate has 100% chance of being included by 2 blocks, // so estimateFee(2) should return 9*baseRate etc... for (int i = 1; i < 10;i++) { origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK()); origPriEst.push_back(mpool.estimatePriority(i)); if (i > 1) { // Fee estimates should be monotonically decreasing - BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); + if (i > 2) { + BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); + } BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]); } int mult = 11-i; - BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); - BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); + if (i > 1) { + BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); + BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); + } + else { + BOOST_CHECK(origFeeEst[i-1] == CFeeRate(0).GetFeePerK()); + } BOOST_CHECK(origPriEst[i-1] < pow(10,mult) * basepri + deltaPri); BOOST_CHECK(origPriEst[i-1] > pow(10,mult) * basepri - deltaPri); } @@ -127,9 +134,12 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) while (blocknum < 250) mpool.removeForBlock(block, ++blocknum, dummyConflicted); + BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); for (int i = 1; i < 10;i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee); - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + if (i > 1) { + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee); + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + } BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri); BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); } @@ -169,8 +179,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) } mpool.removeForBlock(block, 265, dummyConflicted); block.clear(); + BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); for (int i = 1; i < 10;i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); + if (i > 1) + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri); } @@ -190,8 +202,10 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) mpool.removeForBlock(block, ++blocknum, dummyConflicted); block.clear(); } + BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); for (int i = 1; i < 10; i++) { - BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); + if (i > 1) + BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri); } From a710a4304033eea581e463a5fb0502bdb8991aa1 Mon Sep 17 00:00:00 2001 From: wodry Date: Wed, 30 Nov 2016 17:19:08 +0100 Subject: [PATCH 67/91] Improvement of documentation of command line parameter 'whitelist' Github-Pull: #9251 Rebased-From: 8a70a9da3da0df5c376042b18b87f0a63e88d2e3 --- src/init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 4a837018b..bbdab14ee 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -376,7 +376,7 @@ std::string HelpMessage(HelpMessageMode mode) #endif #endif strUsage += HelpMessageOpt("-whitebind=", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6")); - strUsage += HelpMessageOpt("-whitelist=", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") + + strUsage += HelpMessageOpt("-whitelist=", _("Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times.") + " " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway")); strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY)); strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY)); From 21ccb9f2530af996fc0a58df418837a08b75781f Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Sun, 20 Nov 2016 09:54:51 -0500 Subject: [PATCH 68/91] Add option to return non-segwit serialization via rpc Github-Pull: #9194 Rebased-From: 835c75acaac004c3315395dcd7d1f193dfb9e5da --- qa/rpc-tests/segwit.py | 20 +++++++++++++++++--- src/core_io.h | 2 +- src/core_write.cpp | 4 ++-- src/init.cpp | 4 ++++ src/rpc/blockchain.cpp | 2 +- src/rpc/rawtransaction.cpp | 2 +- src/rpc/server.cpp | 8 ++++++++ src/rpc/server.h | 5 +++++ src/wallet/rpcwallet.cpp | 2 +- 9 files changed, 40 insertions(+), 9 deletions(-) diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py index 493ad2e67..4b4fdf8b1 100755 --- a/qa/rpc-tests/segwit.py +++ b/qa/rpc-tests/segwit.py @@ -13,6 +13,7 @@ from test_framework.address import script_to_p2sh, key_to_p2pkh from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG from io import BytesIO +from test_framework.mininode import FromHex NODE_0 = 0 NODE_1 = 1 @@ -83,8 +84,8 @@ def setup_chain(self): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness", "-rpcserialversion=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=2"])) self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"])) connect_nodes(self.nodes[1], 0) connect_nodes(self.nodes[2], 1) @@ -210,7 +211,20 @@ def run_test(self): block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3) sync_blocks(self.nodes) assert_equal(len(self.nodes[2].getrawmempool()), 0) - assert_equal(len(self.nodes[2].getblock(block[0])["tx"]), 5) + segwit_tx_list = self.nodes[2].getblock(block[0])["tx"] + assert_equal(len(segwit_tx_list), 5) + + print("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag") + # Note: node1 has version 2, which is simply >0 and will catch future upgrades in tests + assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False)) + assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False)) + for i in range(len(segwit_tx_list)): + tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) + assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i])) + assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i])) + assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) + assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) + assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness())) print("Verify witness txs without witness data are invalid after the fork") self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False) diff --git a/src/core_io.h b/src/core_io.h index b559d44bf..44a732b69 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -25,7 +25,7 @@ extern std::vector ParseHexUV(const UniValue& v, const std::strin // core_write.cpp extern std::string FormatScript(const CScript& script); -extern std::string EncodeHexTx(const CTransaction& tx); +extern std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0); extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry); diff --git a/src/core_write.cpp b/src/core_write.cpp index ea01ddc10..9f859ba9e 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -116,9 +116,9 @@ string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) return str; } -string EncodeHexTx(const CTransaction& tx) +string EncodeHexTx(const CTransaction& tx, const int serialFlags) { - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags); ssTx << tx; return HexStr(ssTx.begin(), ssTx.end()); } diff --git a/src/init.cpp b/src/init.cpp index bbdab14ee..8e40c4388 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -364,6 +364,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); + strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(>0) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); strUsage += HelpMessageOpt("-torcontrol=:", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); @@ -982,6 +983,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); + if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) + return InitError("rpcserialversion must be non-negative."); + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index a38b3fc60..b4d53a9f3 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -607,7 +607,7 @@ UniValue getblock(const UniValue& params, bool fHelp) if (!fVerbose) { - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); ssBlock << block; std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); return strHex; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index b2bbb8b3e..2719829e6 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -209,7 +209,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp) if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - string strHex = EncodeHexTx(tx); + string strHex = EncodeHexTx(tx, RPCSerializationFlags()); if (!fVerbose) return strHex; diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 102c77631..deeabcb8d 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -495,4 +495,12 @@ void RPCRunLater(const std::string& name, boost::function func, int6 deadlineTimers.insert(std::make_pair(name, boost::shared_ptr(timerInterface->NewTimer(func, nSeconds*1000)))); } +int RPCSerializationFlags() +{ + int flag = 0; + if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) == 0) + flag |= SERIALIZE_TRANSACTION_NO_WITNESS; + return flag; +} + CRPCTable tableRPC; diff --git a/src/rpc/server.h b/src/rpc/server.h index b5ccc153d..1ed8f2466 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -19,6 +19,8 @@ #include +static const unsigned int DEFAULT_RPC_SERIALIZE_VERSION = 1; + class CRPCCommand; namespace RPCServer @@ -195,4 +197,7 @@ void InterruptRPC(); void StopRPC(); std::string JSONRPCExecBatch(const UniValue& vReq); +// Retrieves any serialization flags requested in command line argument +int RPCSerializationFlags(); + #endif // BITCOIN_RPCSERVER_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fdb7a53d3..17bda050c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1780,7 +1780,7 @@ UniValue gettransaction(const UniValue& params, bool fHelp) ListTransactions(wtx, "*", 0, false, details, filter); entry.push_back(Pair("details", details)); - string strHex = EncodeHexTx(static_cast(wtx)); + string strHex = EncodeHexTx(static_cast(wtx), RPCSerializationFlags()); entry.push_back(Pair("hex", strHex)); return entry; From f26dab7e90cfb1733736c1dd63c507254de84a34 Mon Sep 17 00:00:00 2001 From: instagibbs Date: Tue, 22 Nov 2016 15:47:07 -0500 Subject: [PATCH 69/91] Adapt ZMQ/rest serialization to take rpcserialversion arg Github-Pull: #9194 Rebased-From: ad5c4c93cae53a2a6f74880ca11b4d788677a378 --- src/rest.cpp | 4 ++-- src/zmq/zmqpublishnotifier.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/rest.cpp b/src/rest.cpp index 2dff8d7da..57cd9baeb 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -228,7 +228,7 @@ static bool rest_block(HTTPRequest* req, return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); ssBlock << block; switch (rf) { @@ -367,7 +367,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); ssTx << tx; switch (rf) { diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index b6c907980..cdef17e08 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -6,6 +6,7 @@ #include "zmqpublishnotifier.h" #include "main.h" #include "util.h" +#include "rpc/server.h" static std::multimap mapPublishNotifiers; @@ -165,7 +166,7 @@ bool CZMQPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) LogPrint("zmq", "zmq: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); const Consensus::Params& consensusParams = Params().GetConsensus(); - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); { LOCK(cs_main); CBlock block; @@ -185,7 +186,7 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &tr { uint256 hash = transaction.GetHash(); LogPrint("zmq", "zmq: Publish rawtx %s\n", hash.GetHex()); - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags()); ss << transaction; return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size()); } From 4c71fc42fbf32d8994f4d2488ac4bafad93226a1 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 30 Sep 2016 18:19:57 -0400 Subject: [PATCH 70/91] Remove duplicate nBlocksEstimate cmp (we already checked IsIBD()) Github-Pull: #8865 Rebased-From: 0278fb5f48ae9e42ec0772f85e201051077f633c --- src/main.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 191bcff4c..cfc616201 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3110,13 +3110,10 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, } } // Relay inventory, but don't relay old inventory during initial block download. - int nBlockEstimate = 0; - if (fCheckpointsEnabled) - nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()); { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { + if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) { BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) { pnode->PushBlockHash(hash); } From ad20cddce2097c6561202777fccd257deb1a9810 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sat, 22 Oct 2016 05:33:25 +0000 Subject: [PATCH 71/91] IBD check uses minimumchain work instead of checkpoints. This introduces a 'minimum chain work' chainparam which is intended to be the known amount of work in the chain for the network at the time of software release. If you don't have this much work, you're not yet caught up. This is used instead of the count of blocks test from checkpoints. This criteria is trivial to keep updated as there is no element of subjectivity, trust, or position dependence to it. It is also a more reliable metric of sync status than a block count. Github-Pull: #9053 Rebased-From: fd46136dfaf68a7046cf7b8693824d73ac6b1caf --- doc/release-process.md | 1 + src/chainparams.cpp | 10 ++++++++++ src/consensus/params.h | 1 + src/main.cpp | 6 ++++-- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/release-process.md b/doc/release-process.md index 41c1ac855..ccc4bcd23 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -10,6 +10,7 @@ Before every minor and major release: * Update [bips.md](bips.md) to account for changes since the last release. * Update version in sources (see below) * Write release notes (see below) +* Update `src/chainparams.cpp` nMinimumChainWork with information from the getblockchaininfo rpc. Before every major release: diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3ad9f4d2d..69514617b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -97,6 +97,9 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1479168000; // November 15th, 2016. consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017. + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000002cb971dd56d1c583c20f90"); + /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce @@ -194,6 +197,9 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016 consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017 + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000198b4def2baa9338d6"); + pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; pchMessageStart[2] = 0x09; @@ -228,6 +234,7 @@ class CTestNetParams : public CChainParams { fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = true; + checkpointData = (CCheckpointData) { boost::assign::map_list_of ( 546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")), @@ -270,6 +277,9 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 999999999999ULL; + // The best chain should have at least this much work. + consensus.nMinimumChainWork = uint256S("0x00"); + pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; diff --git a/src/consensus/params.h b/src/consensus/params.h index d97017d0c..7aa876d65 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -61,6 +61,7 @@ struct Params { int64_t nPowTargetSpacing; int64_t nPowTargetTimespan; int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } + uint256 nMinimumChainWork; }; } // namespace Consensus diff --git a/src/main.cpp b/src/main.cpp index cfc616201..54eff56f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1747,7 +1747,9 @@ bool IsInitialBlockDownload() return false; if (fImporting || fReindex) return true; - if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) + if (chainActive.Tip() == NULL) + return true; + if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) return true; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || std::max(chainActive.Tip()->GetBlockTime(), pindexBestHeader->GetBlockTime()) < GetTime() - nMaxTipAge); @@ -1781,7 +1783,7 @@ void CheckForkWarningConditions() { 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 the last checkpoint) + // (we assume we don't get stuck on a fork before finishing our initial sync) if (IsInitialBlockDownload()) return; From 5b93eeebb4f7fce10a12f2e83f771bc23002c224 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Wed, 2 Nov 2016 01:49:45 +0000 Subject: [PATCH 72/91] Remove GetTotalBlocksEstimate and checkpoint tests that test nothing. GetTotalBlocksEstimate is no longer used and it was the only thing the checkpoint tests were testing. Since checkpoints are on their way out it makes more sense to remove the test file than to cook up a new pointless test. Github-Pull: #9053 Rebased-From: 2082b5574cec783f4ff99941492d92e05680b293 --- src/Makefile.test.include | 1 - src/checkpoints.cpp | 10 ---------- src/checkpoints.h | 3 --- src/test/Checkpoints_tests.cpp | 27 --------------------------- 4 files changed, 41 deletions(-) delete mode 100644 src/test/Checkpoints_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index ef30eeb4a..0878d8234 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -50,7 +50,6 @@ BITCOIN_TESTS =\ test/bip32_tests.cpp \ test/blockencodings_tests.cpp \ test/bloom_tests.cpp \ - test/Checkpoints_tests.cpp \ test/coins_tests.cpp \ test/compress_tests.cpp \ test/crypto_tests.cpp \ diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index aefddce46..d22c188c1 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -55,16 +55,6 @@ namespace Checkpoints { return fWorkBefore / (fWorkBefore + fWorkAfter); } - int GetTotalBlocksEstimate(const CCheckpointData& data) - { - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - if (checkpoints.empty()) - return 0; - - return checkpoints.rbegin()->first; - } - CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) { const MapCheckpoints& checkpoints = data.mapCheckpoints; diff --git a/src/checkpoints.h b/src/checkpoints.h index cd25ea537..04346f35f 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -19,9 +19,6 @@ struct CCheckpointData; namespace Checkpoints { -//! Return conservative estimate of total number of blocks, 0 if unknown -int GetTotalBlocksEstimate(const CCheckpointData& data); - //! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(const CCheckpointData& data); diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp deleted file mode 100644 index 1b7d368e1..000000000 --- a/src/test/Checkpoints_tests.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2011-2015 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// -// Unit tests for block-chain checkpoints -// - -#include "checkpoints.h" - -#include "uint256.h" -#include "test/test_bitcoin.h" -#include "chainparams.h" - -#include - -using namespace std; - -BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup) - -BOOST_AUTO_TEST_CASE(sanity) -{ - const CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints(); - BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444); -} - -BOOST_AUTO_TEST_SUITE_END() From 5998a09546b033e8d55f2a45d35a6161b2cdc288 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Tue, 1 Nov 2016 00:37:54 +0000 Subject: [PATCH 73/91] IsInitialBlockDownload no longer uses header-only timestamps. This avoids a corner case (mostly visible on testnet) where bogus headers can keep nodes in IsInitialBlockDownload. Github-Pull: #9053 Rebased-From: e141beb6a9816b7e1e680fb0a8bae16d42a3e557 --- src/main.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 54eff56f4..5f04c1916 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1751,11 +1751,10 @@ bool IsInitialBlockDownload() return true; if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) return true; - bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - std::max(chainActive.Tip()->GetBlockTime(), pindexBestHeader->GetBlockTime()) < GetTime() - nMaxTipAge); - if (!state) - latchToFalse.store(true, std::memory_order_relaxed); - return state; + if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) + return true; + latchToFalse.store(true, std::memory_order_relaxed); + return false; } bool fLargeWorkForkFound = false; From 57aec3b0b5993568571c352643abb6f3d79ffdd7 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Sun, 11 Dec 2016 21:17:20 +0000 Subject: [PATCH 74/91] Add release notes for wallet/mempool rejections. (PR #9302 and #9290) --- doc/release-notes.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index e54f9ac02..0830e0a12 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -42,8 +42,23 @@ but severe issues with the libc++ version on 10.7.x keep it from running reliabl Notable changes =============== -Example item ---------------- +Change to wallet handling of mempool rejection +----------------------------------------------- + +When a newly created transaction failed to enter the mempool due to +the limits on chains of unconfirmed transactions the sending RPC +calls would return an error. The transaction would still be queued +in the wallet and, once some of the parent transactions were +confirmed, broadcast after the software was restarted. + +This behavior has been changed to return success and to reattempt +mempool insertion at the same time transaction rebroadcast is +attempted, avoiding a need for a restart. + +Transactions in the wallet which cannot be accepted into the mempool +can be abandoned with the previously existing abandontransaction RPC +(or in the GUI via a context menu on the transaction). + 0.13.x Change log ================= From 64dfdde0aa7f7ef24e6cbf3c57e6d24efc55367e Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 13 Dec 2016 12:37:40 +0100 Subject: [PATCH 75/91] Squashed 'src/secp256k1/' changes from 6c527ec..8225239 8225239 Merge #433: Make the libcrypto detection fail the newer API. 12de863 Make the libcrypto detection fail the newer API. 2928420 Merge #427: Remove Schnorr from travis as well 8eecc4a Remove Schnorr from travis as well a8abae7 Merge #310: Add exhaustive test for group functions on a low-order subgroup b4ceedf Add exhaustive test for verification 83836a9 Add exhaustive tests for group arithmetic, signing, and ecmult on a small group 20b8877 Add exhaustive test for group functions on a low-order subgroup 80773a6 Merge #425: Remove Schnorr experiment e06e878 Remove Schnorr experiment 04c8ef3 Merge #407: Modify parameter order of internal functions to match API parameter order 6e06696 Merge #411: Remove guarantees about memcmp-ability 40c8d7e Merge #421: Update scalar_4x64_impl.h a922365 Merge #422: Restructure nonce clearing 3769783 Restructure nonce clearing 0f9e69d Restructure nonce clearing 9d67afa Update scalar_4x64_impl.h 7d15cd7 Merge #413: fix auto-enabled static precompuatation 00c5d2e fix auto-enabled static precompuatation 91219a1 Remove guarantees about memcmp-ability 7a49cac Merge #410: Add string.h include to ecmult_impl 0bbd5d4 Add string.h include to ecmult_impl 353c1bf Fix secp256k1_ge_set_table_gej_var parameter order 541b783 Fix secp256k1_ge_set_all_gej_var parameter order 7d893f4 Fix secp256k1_fe_inv_all_var parameter order c5b32e1 Merge #405: Make secp256k1_fe_sqrt constant time 926836a Make secp256k1_fe_sqrt constant time e2a8e92 Merge #404: Replace 3M + 4S doubling formula with 2M + 5S one 8ec49d8 Add note about 2M + 5S doubling formula 5a91bd7 Merge #400: A couple minor cleanups ac01378 build: add -DSECP256K1_BUILD to benchmark_internal build flags a6c6f99 Remove a bunch of unused stdlib #includes 65285a6 Merge #403: configure: add flag to disable OpenSSL tests a9b2a5d configure: add flag to disable OpenSSL tests b340123 Merge #402: Add support for testing quadratic residues e6e9805 Add function for testing quadratic residue field/group elements. efd953a Add Jacobi symbol test via GMP fa36a0d Merge #401: ecmult_const: unify endomorphism and non-endomorphism skew cases c6191fd ecmult_const: unify endomorphism and non-endomorphism skew cases 0b3e618 Merge #378: .gitignore build-aux cleanup 6042217 Merge #384: JNI: align shared files copyright/comments to bitcoinj's 24ad20f Merge #399: build: verify that the native compiler works for static precomp b3be852 Merge #398: Test whether ECDH and Schnorr are enabled for JNI aa0b1fd build: verify that the native compiler works for static precomp eee808d Test whether ECDH and Schnorr are enabled for JNI 7b0fb18 Merge #366: ARM assembly implementation of field_10x26 inner (rebase of #173) 001f176 ARM assembly implementation of field_10x26 inner 0172be9 Merge #397: Small fixes for sha256 3f8b78e Fix undefs in hash_impl.h 2ab4695 Fix state size in sha256 struct 6875b01 Merge #386: Add some missing `VERIFY_CHECK(ctx != NULL)` 2c52b5d Merge #389: Cast pointers through uintptr_t under JNI 43097a4 Merge #390: Update bitcoin-core GitHub links 31c9c12 Merge #391: JNI: Only call ecdsa_verify if its inputs parsed correctly 1cb2302 Merge #392: Add testcase which hits additional branch in secp256k1_scalar_sqr d2ee340 Merge #388: bench_ecdh: fix call to secp256k1_context_create 093a497 Add testcase which hits additional branch in secp256k1_scalar_sqr a40c701 JNI: Only call ecdsa_verify if its inputs parsed correctly faa2a11 Update bitcoin-core GitHub links 47b9e78 Cast pointers through uintptr_t under JNI f36f9c6 bench_ecdh: fix call to secp256k1_context_create bcc4881 Add some missing `VERIFY_CHECK(ctx != NULL)` for functions that use `ARG_CHECK` 6ceea2c align shared files copyright/comments to bitcoinj's 70141a8 Update .gitignore 7b549b1 Merge #373: build: fix x86_64 asm detection for some compilers bc7c93c Merge #374: Add note about y=0 being possible on one of the sextic twists e457018 Merge #364: JNI rebased 86e2d07 JNI library: cleanup, removed unimplemented code 3093576a JNI library bd2895f Merge pull request #371 e72e93a Add note about y=0 being possible on one of the sextic twists 3f8fdfb build: fix x86_64 asm detection for some compilers e5a9047 [Trivial] Remove double semicolons c18b869 Merge pull request #360 3026daa Merge pull request #302 03d4611 Add sage verification script for the group laws a965937 Merge pull request #361 83221ec Add experimental features to configure 5d4c5a3 Prevent damage_array in the signature test from going out of bounds. 419bf7f Merge pull request #356 03d84a4 Benchmark against OpenSSL verification git-subtree-dir: src/secp256k1 git-subtree-split: 8225239f490f79842a5a3b82ad6cc8aa11d5208e --- .gitignore | 20 +- .travis.yml | 18 +- Makefile.am | 90 +- README.md | 2 +- build-aux/m4/ax_jni_include_dir.m4 | 140 +++ build-aux/m4/bitcoin_secp.m4 | 8 +- configure.ac | 158 ++- include/secp256k1.h | 14 +- include/secp256k1_schnorr.h | 173 ---- libsecp256k1.pc.in | 2 +- sage/group_prover.sage | 322 ++++++ sage/secp256k1.sage | 306 ++++++ sage/weierstrass_prover.sage | 264 +++++ src/asm/field_10x26_arm.s | 919 ++++++++++++++++++ src/bench_ecdh.c | 3 +- src/bench_internal.c | 34 +- src/bench_verify.c | 44 + src/ecdsa_impl.h | 18 + src/ecmult_const_impl.h | 69 +- src/ecmult_gen_impl.h | 2 +- src/ecmult_impl.h | 21 +- src/field.h | 15 +- src/field_10x26_impl.h | 12 +- src/field_5x52_impl.h | 1 - src/field_5x52_int128_impl.h | 4 +- src/field_impl.h | 38 +- src/group.h | 9 +- src/group_impl.h | 112 ++- src/hash.h | 2 +- src/hash_impl.h | 10 +- src/java/org/bitcoin/NativeSecp256k1.java | 440 ++++++++- src/java/org/bitcoin/NativeSecp256k1Test.java | 226 +++++ src/java/org/bitcoin/NativeSecp256k1Util.java | 45 + src/java/org/bitcoin/Secp256k1Context.java | 51 + src/java/org_bitcoin_NativeSecp256k1.c | 378 ++++++- src/java/org_bitcoin_NativeSecp256k1.h | 104 +- src/java/org_bitcoin_Secp256k1Context.c | 15 + src/java/org_bitcoin_Secp256k1Context.h | 22 + src/modules/ecdh/Makefile.am.include | 2 +- src/modules/recovery/Makefile.am.include | 2 +- src/modules/recovery/main_impl.h | 4 +- src/modules/schnorr/Makefile.am.include | 10 - src/modules/schnorr/main_impl.h | 164 ---- src/modules/schnorr/schnorr.h | 20 - src/modules/schnorr/schnorr_impl.h | 207 ---- src/modules/schnorr/tests_impl.h | 175 ---- src/num.h | 6 + src/num_gmp_impl.h | 26 + src/scalar.h | 4 +- src/scalar_4x64_impl.h | 26 +- src/scalar_impl.h | 41 +- src/scalar_low.h | 15 + src/scalar_low_impl.h | 114 +++ src/secp256k1.c | 19 +- src/tests.c | 202 +++- src/tests_exhaustive.c | 329 +++++++ 56 files changed, 4463 insertions(+), 1014 deletions(-) create mode 100644 build-aux/m4/ax_jni_include_dir.m4 delete mode 100644 include/secp256k1_schnorr.h create mode 100644 sage/group_prover.sage create mode 100644 sage/secp256k1.sage create mode 100644 sage/weierstrass_prover.sage create mode 100644 src/asm/field_10x26_arm.s create mode 100644 src/java/org/bitcoin/NativeSecp256k1Test.java create mode 100644 src/java/org/bitcoin/NativeSecp256k1Util.java create mode 100644 src/java/org/bitcoin/Secp256k1Context.java create mode 100644 src/java/org_bitcoin_Secp256k1Context.c create mode 100644 src/java/org_bitcoin_Secp256k1Context.h mode change 100644 => 100755 src/modules/recovery/main_impl.h delete mode 100644 src/modules/schnorr/Makefile.am.include delete mode 100644 src/modules/schnorr/main_impl.h delete mode 100644 src/modules/schnorr/schnorr.h delete mode 100644 src/modules/schnorr/schnorr_impl.h delete mode 100644 src/modules/schnorr/tests_impl.h create mode 100644 src/scalar_low.h create mode 100644 src/scalar_low_impl.h mode change 100644 => 100755 src/secp256k1.c create mode 100644 src/tests_exhaustive.c diff --git a/.gitignore b/.gitignore index e0b7b7a48..87fea161b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ bench_schnorr_verify bench_recover bench_internal tests +exhaustive_tests gen_context *.exe *.so @@ -25,17 +26,24 @@ config.status libtool .deps/ .dirstamp -build-aux/ *.lo *.o *~ src/libsecp256k1-config.h src/libsecp256k1-config.h.in src/ecmult_static_context.h -m4/libtool.m4 -m4/ltoptions.m4 -m4/ltsugar.m4 -m4/ltversion.m4 -m4/lt~obsolete.m4 +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver src/stamp-h1 libsecp256k1.pc diff --git a/.travis.yml b/.travis.yml index 4e1e73c39..243952924 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,26 +6,30 @@ addons: compiler: - clang - gcc +cache: + directories: + - src/java/guava/ env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no + - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar matrix: - SCALAR=32bit RECOVERY=yes - - SCALAR=32bit FIELD=32bit ECDH=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes - SCALAR=64bit - FIELD=64bit RECOVERY=yes - FIELD=64bit ENDOMORPHISM=yes - - FIELD=64bit ENDOMORPHISM=yes ECDH=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit SCHNORR=yes - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC - EXTRAFLAGS=CFLAGS=-O0 + - BUILD=check-java ECDH=yes EXPERIMENTAL=yes matrix: fast_finish: true include: @@ -55,9 +59,11 @@ matrix: packages: - gcc-multilib - libgmp-dev:i386 +before_install: mkdir -p `dirname $GUAVA_JAR` +install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD os: linux diff --git a/Makefile.am b/Makefile.am index 7772a4e9d..e5657f7f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,14 +1,22 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 lib_LTLIBRARIES = libsecp256k1.la +if USE_JNI +JNI_LIB = libsecp256k1_jni.la +noinst_LTLIBRARIES = $(JNI_LIB) +else +JNI_LIB = +endif include_HEADERS = include/secp256k1.h noinst_HEADERS = noinst_HEADERS += src/scalar.h noinst_HEADERS += src/scalar_4x64.h noinst_HEADERS += src/scalar_8x32.h +noinst_HEADERS += src/scalar_low.h noinst_HEADERS += src/scalar_impl.h noinst_HEADERS += src/scalar_4x64_impl.h noinst_HEADERS += src/scalar_8x32_impl.h +noinst_HEADERS += src/scalar_low_impl.h noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h noinst_HEADERS += src/num_gmp.h @@ -32,6 +40,7 @@ noinst_HEADERS += src/field_5x52_impl.h noinst_HEADERS += src/field_5x52_int128_impl.h noinst_HEADERS += src/field_5x52_asm_impl.h noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h +noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h noinst_HEADERS += src/util.h noinst_HEADERS += src/testrand.h noinst_HEADERS += src/testrand_impl.h @@ -45,33 +54,88 @@ noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.h noinst_HEADERS += contrib/lax_der_privatekey_parsing.c +if USE_EXTERNAL_ASM +COMMON_LIB = libsecp256k1_common.la +noinst_LTLIBRARIES = $(COMMON_LIB) +else +COMMON_LIB = +endif + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc +if USE_EXTERNAL_ASM +if USE_ASM_ARM +libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s +endif +endif + libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) -libsecp256k1_la_LIBADD = $(SECP_LIBS) +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) +libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c +libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) noinst_PROGRAMS = if USE_BENCHMARK noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_verify_SOURCES = src/bench_verify.c -bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_sign_SOURCES = src/bench_sign.c -bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(SECP_LIBS) -bench_internal_CPPFLAGS = $(SECP_INCLUDES) +bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) +bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) endif +TESTS = if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) -tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) +tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) tests_LDFLAGS = -static -TESTS = tests +TESTS += tests +endif + +if USE_EXHAUSTIVE_TESTS +noinst_PROGRAMS += exhaustive_tests +exhaustive_tests_SOURCES = src/tests_exhaustive.c +exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src $(SECP_INCLUDES) +exhaustive_tests_LDADD = $(SECP_LIBS) +exhaustive_tests_LDFLAGS = -static +TESTS += exhaustive_tests +endif + +JAVAROOT=src/java +JAVAORG=org/bitcoin +JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar +CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) +JAVA_FILES= \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ + $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java + +if USE_JNI + +$(JAVA_GUAVA): + @echo Guava is missing. Fetch it via: \ + wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) + @false + +.stamp-java: $(JAVA_FILES) + @echo Compiling $^ + $(AM_V_at)$(CLASSPATH_ENV) javac $^ + @touch $@ + +if USE_TESTS + +check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java + $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + +endif endif if USE_ECMULT_STATIC_PRECOMPUTATION @@ -93,19 +157,15 @@ $(bench_internal_OBJECTS): src/ecmult_static_context.h src/ecmult_static_context.h: $(gen_context_BIN) ./$(gen_context_BIN) -CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java endif -EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) if ENABLE_MODULE_ECDH include src/modules/ecdh/Makefile.am.include endif -if ENABLE_MODULE_SCHNORR -include src/modules/schnorr/Makefile.am.include -endif - if ENABLE_MODULE_RECOVERY include src/modules/recovery/Makefile.am.include endif diff --git a/README.md b/README.md index 6095db422..8cd344ea8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ libsecp256k1 ============ -[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1) +[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1) Optimized C library for EC operations on curve secp256k1. diff --git a/build-aux/m4/ax_jni_include_dir.m4 b/build-aux/m4/ax_jni_include_dir.m4 new file mode 100644 index 000000000..1fc362761 --- /dev/null +++ b/build-aux/m4/ax_jni_include_dir.m4 @@ -0,0 +1,140 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_JNI_INCLUDE_DIR +# +# DESCRIPTION +# +# AX_JNI_INCLUDE_DIR finds include directories needed for compiling +# programs using the JNI interface. +# +# JNI include directories are usually in the Java distribution. This is +# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in +# that order. When this macro completes, a list of directories is left in +# the variable JNI_INCLUDE_DIRS. +# +# Example usage follows: +# +# AX_JNI_INCLUDE_DIR +# +# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +# do +# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" +# done +# +# If you want to force a specific compiler: +# +# - at the configure.in level, set JAVAC=yourcompiler before calling +# AX_JNI_INCLUDE_DIR +# +# - at the configure level, setenv JAVAC +# +# Note: This macro can work with the autoconf M4 macros for Java programs. +# This particular macro is not part of the original set of macros. +# +# LICENSE +# +# Copyright (c) 2008 Don Anderson +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) +AC_DEFUN([AX_JNI_INCLUDE_DIR],[ + +JNI_INCLUDE_DIRS="" + +if test "x$JAVA_HOME" != x; then + _JTOPDIR="$JAVA_HOME" +else + if test "x$JAVAC" = x; then + JAVAC=javac + fi + AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) + if test "x$_ACJNI_JAVAC" = xno; then + AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) + fi + _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") + _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` +fi + +case "$host_os" in + darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + _JINC="$_JTOPDIR/Headers";; + *) _JINC="$_JTOPDIR/include";; +esac +_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) +_AS_ECHO_LOG([_JINC=$_JINC]) + +# On Mac OS X 10.6.4, jni.h is a symlink: +# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h +# -> ../../CurrentJDK/Headers/jni.h. + +AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, +[ +if test -f "$_JINC/jni.h"; then + ac_cv_jni_header_path="$_JINC" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" +else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$_JTOPDIR/include/jni.h"; then + ac_cv_jni_header_path="$_JTOPDIR/include" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + ac_cv_jni_header_path=none + fi +fi +]) + + + +# get the likely subdirectories for system specific java includes +case "$host_os" in +bsdi*) _JNI_INC_SUBDIRS="bsdos";; +darwin*) _JNI_INC_SUBDIRS="darwin";; +freebsd*) _JNI_INC_SUBDIRS="freebsd";; +linux*) _JNI_INC_SUBDIRS="linux genunix";; +osf*) _JNI_INC_SUBDIRS="alpha";; +solaris*) _JNI_INC_SUBDIRS="solaris";; +mingw*) _JNI_INC_SUBDIRS="win32";; +cygwin*) _JNI_INC_SUBDIRS="win32";; +*) _JNI_INC_SUBDIRS="genunix";; +esac + +if test "x$ac_cv_jni_header_path" != "xnone"; then + # add any subdirectories that are present + for JINCSUBDIR in $_JNI_INC_SUBDIRS + do + if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" + fi + done +fi +]) + +# _ACJNI_FOLLOW_SYMLINKS +# Follows symbolic links on , +# finally setting variable _ACJNI_FOLLOWED +# ---------------------------------------- +AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING([symlink for $_cur]) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT([$_cur]) +done +_ACJNI_FOLLOWED="$_cur" +])# _ACJNI diff --git a/build-aux/m4/bitcoin_secp.m4 b/build-aux/m4/bitcoin_secp.m4 index d41bbb648..b74acb8c1 100644 --- a/build-aux/m4/bitcoin_secp.m4 +++ b/build-aux/m4/bitcoin_secp.m4 @@ -3,13 +3,13 @@ AC_DEFUN([SECP_INT128_CHECK],[ has_int128=$ac_cv_type___int128 ]) -dnl +dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. AC_DEFUN([SECP_64BIT_ASM_CHECK],[ AC_MSG_CHECKING(for x86_64 assembly availability) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include ]],[[ uint64_t a = 11, tmp; - __asm__ __volatile__("movq $0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); + __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) AC_MSG_RESULT([$has_64bit_asm]) ]) @@ -46,6 +46,10 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); ECDSA_verify(0, NULL, 0, NULL, 0, eckey); EC_KEY_free(eckey); + ECDSA_SIG *sig_openssl; + sig_openssl = ECDSA_SIG_new(); + (void)sig_openssl->r; + ECDSA_SIG_free(sig_openssl); ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) AC_MSG_RESULT([$has_openssl_ec]) fi diff --git a/configure.ac b/configure.ac index 786d8dcfb..ec50ffe3a 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ AC_PROG_CC_C89 if test x"$ac_cv_prog_cc_c89" = x"no"; then AC_MSG_ERROR([c89 compiler support required]) fi +AM_PROG_AS case $host_os in *darwin*) @@ -93,31 +94,46 @@ AC_ARG_ENABLE(tests, [use_tests=$enableval], [use_tests=yes]) +AC_ARG_ENABLE(openssl_tests, + AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), + [enable_openssl_tests=$enableval], + [enable_openssl_tests=auto]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), + [use_experimental=$enableval], + [use_experimental=no]) + +AC_ARG_ENABLE(exhaustive_tests, + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), + [use_exhaustive_tests=$enableval], + [use_exhaustive_tests=yes]) + AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is 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 is yes)]), [use_ecmult_static_precomputation=$enableval], - [use_ecmult_static_precomputation=yes]) + [use_ecmult_static_precomputation=auto]) AC_ARG_ENABLE(module_ecdh, - AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (default is no)]), + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), [enable_module_ecdh=$enableval], [enable_module_ecdh=no]) -AC_ARG_ENABLE(module_schnorr, - AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (default is no)]), - [enable_module_schnorr=$enableval], - [enable_module_schnorr=no]) - AC_ARG_ENABLE(module_recovery, AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), [enable_module_recovery=$enableval], [enable_module_recovery=no]) +AC_ARG_ENABLE(jni, + AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]), + [use_jni=$enableval], + [use_jni=auto]) + AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) @@ -127,8 +143,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], [Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto] -[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto]) +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] +[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) AC_CHECK_TYPES([__int128]) @@ -138,6 +154,34 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], [ AC_MSG_RESULT([no]) ]) +if test x"$use_ecmult_static_precomputation" != x"no"; then + save_cross_compiling=$cross_compiling + cross_compiling=no + TEMP_CC="$CC" + CC="$CC_FOR_BUILD" + AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], [return 0])], + [working_native_cc=yes], + [working_native_cc=no],[dnl]) + CC="$TEMP_CC" + cross_compiling=$save_cross_compiling + + if test x"$working_native_cc" = x"no"; then + set_precomp=no + if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + else + AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + fi + else + AC_MSG_RESULT([ok]) + set_precomp=yes + fi +else + set_precomp=no +fi + if test x"$req_asm" = x"auto"; then SECP_64BIT_ASM_CHECK if test x"$has_64bit_asm" = x"yes"; then @@ -155,6 +199,8 @@ else AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) fi ;; + arm) + ;; no) ;; *) @@ -247,10 +293,15 @@ else fi # select assembly optimization +use_external_asm=no + case $set_asm in x86_64) AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) ;; +arm) + use_external_asm=yes + ;; no) ;; *) @@ -305,16 +356,48 @@ esac if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK if test x"$has_openssl_ec" = x"yes"; then - AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) - SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" - SECP_TEST_LIBS="$CRYPTO_LIBS" - - case $host in - *mingw*) - SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" - ;; - esac + if test x"$enable_openssl_tests" != x"no"; then + AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) + SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" + SECP_TEST_LIBS="$CRYPTO_LIBS" + + case $host in + *mingw*) + 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 + fi +else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) + fi +fi +if test x"$use_jni" != x"no"; then + AX_JNI_INCLUDE_DIR + have_jni_dependencies=yes + if test x"$enable_module_ecdh" = x"no"; then + have_jni_dependencies=no + fi + if test "x$JNI_INCLUDE_DIRS" = "x"; then + have_jni_dependencies=no + fi + if test "x$have_jni_dependencies" = "xno"; then + if test x"$use_jni" = x"yes"; then + AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.]) + fi + AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) + use_jni=no + else + use_jni=yes + for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do + JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" + done fi fi @@ -327,7 +410,7 @@ if test x"$use_endomorphism" = x"yes"; then AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi -if test x"$use_ecmult_static_precomputation" = x"yes"; then +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 @@ -335,38 +418,57 @@ if test x"$enable_module_ecdh" = x"yes"; then AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) fi -if test x"$enable_module_schnorr" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) -fi - if test x"$enable_module_recovery" = x"yes"; then AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) fi AC_C_BIGENDIAN() +if test x"$use_external_asm" = x"yes"; then + AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) +fi + +AC_MSG_NOTICE([Using static precomputation: $set_precomp]) AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) - -AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) +AC_MSG_NOTICE([Using jni: $use_jni]) + +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([******]) +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"$set_asm" = x"arm"; then + AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) + fi +fi AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(JNI_INCLUDES) AC_SUBST(SECP_INCLUDES) AC_SUBST(SECP_LIBS) AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) +AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) -AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"]) +AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) +AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) dnl make sure nothing new is exported so that we don't break the cache PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" diff --git a/include/secp256k1.h b/include/secp256k1.h index 7145dbcc5..f268e309d 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -47,11 +47,8 @@ typedef struct secp256k1_context_struct secp256k1_context; * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage or transmission, use - * secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. - * - * Furthermore, it is guaranteed that identical public keys (ignoring - * compression) will have identical representation, so they can be memcmp'ed. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. */ typedef struct { unsigned char data[64]; @@ -62,12 +59,9 @@ typedef struct { * The exact representation of data inside is implementation defined and not * guaranteed to be portable between different platforms or versions. It is * however guaranteed to be 64 bytes in size, and can be safely copied/moved. - * If you need to convert to a format suitable for storage or transmission, use - * the secp256k1_ecdsa_signature_serialize_* and + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the secp256k1_ecdsa_signature_serialize_* and * secp256k1_ecdsa_signature_serialize_* functions. - * - * Furthermore, it is guaranteed to identical signatures will have identical - * representation, so they can be memcmp'ed. */ typedef struct { unsigned char data[64]; diff --git a/include/secp256k1_schnorr.h b/include/secp256k1_schnorr.h deleted file mode 100644 index dc32fec1e..000000000 --- a/include/secp256k1_schnorr.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef _SECP256K1_SCHNORR_ -# define _SECP256K1_SCHNORR_ - -# include "secp256k1.h" - -# ifdef __cplusplus -extern "C" { -# endif - -/** Create a signature using a custom EC-Schnorr-SHA256 construction. It - * produces non-malleable 64-byte signatures which support public key recovery - * batch validation, and multiparty signing. - * Returns: 1: signature created - * 0: the nonce generation function failed, or the private key was - * invalid. - * Args: ctx: pointer to a context object, initialized for signing - * (cannot be NULL) - * Out: sig64: pointer to a 64-byte array where the signature will be - * placed (cannot be NULL) - * In: msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation - * function (can be NULL) - */ -SECP256K1_API int secp256k1_schnorr_sign( - const secp256k1_context* ctx, - unsigned char *sig64, - const unsigned char *msg32, - const unsigned char *seckey, - secp256k1_nonce_function noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Verify a signature created by secp256k1_schnorr_sign. - * Returns: 1: correct signature - * 0: incorrect signature - * Args: ctx: a secp256k1 context object, initialized for verification. - * In: sig64: the 64-byte signature being verified (cannot be NULL) - * msg32: the 32-byte message hash being verified (cannot be NULL) - * pubkey: the public key to verify with (cannot be NULL) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( - const secp256k1_context* ctx, - const unsigned char *sig64, - const unsigned char *msg32, - const secp256k1_pubkey *pubkey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Recover an EC public key from a Schnorr signature created using - * secp256k1_schnorr_sign. - * Returns: 1: public key successfully recovered (which guarantees a correct - * signature). - * 0: otherwise. - * Args: ctx: pointer to a context object, initialized for - * verification (cannot be NULL) - * Out: pubkey: pointer to a pubkey to set to the recovered public key - * (cannot be NULL). - * In: sig64: signature as 64 byte array (cannot be NULL) - * msg32: the 32-byte message hash assumed to be signed (cannot - * be NULL) - */ -SECP256K1_API int secp256k1_schnorr_recover( - const secp256k1_context* ctx, - secp256k1_pubkey *pubkey, - const unsigned char *sig64, - const unsigned char *msg32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Generate a nonce pair deterministically for use with - * secp256k1_schnorr_partial_sign. - * Returns: 1: valid nonce pair was generated. - * 0: otherwise (nonce generation function failed) - * Args: ctx: pointer to a context object, initialized for signing - * (cannot be NULL) - * Out: pubnonce: public side of the nonce (cannot be NULL) - * privnonce32: private side of the nonce (32 byte) (cannot be NULL) - * In: msg32: the 32-byte message hash assumed to be signed (cannot - * be NULL) - * sec32: the 32-byte private key (cannot be NULL) - * noncefp: pointer to a nonce generation function. If NULL, - * secp256k1_nonce_function_default is used - * noncedata: pointer to arbitrary data used by the nonce generation - * function (can be NULL) - * - * Do not use the output as a private/public key pair for signing/validation. - */ -SECP256K1_API int secp256k1_schnorr_generate_nonce_pair( - const secp256k1_context* ctx, - secp256k1_pubkey *pubnonce, - unsigned char *privnonce32, - const unsigned char *msg32, - const unsigned char *sec32, - secp256k1_nonce_function noncefp, - const void* noncedata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -/** Produce a partial Schnorr signature, which can be combined using - * secp256k1_schnorr_partial_combine, to end up with a full signature that is - * verifiable using secp256k1_schnorr_verify. - * Returns: 1: signature created successfully. - * 0: no valid signature exists with this combination of keys, nonces - * and message (chance around 1 in 2^128) - * -1: invalid private key, nonce, or public nonces. - * Args: ctx: pointer to context object, initialized for signing (cannot - * be NULL) - * Out: sig64: pointer to 64-byte array to put partial signature in - * In: msg32: pointer to 32-byte message to sign - * sec32: pointer to 32-byte private key - * pubnonce_others: pointer to pubkey containing the sum of the other's - * nonces (see secp256k1_ec_pubkey_combine) - * secnonce32: pointer to 32-byte array containing our nonce - * - * The intended procedure for creating a multiparty signature is: - * - Each signer S[i] with private key x[i] and public key Q[i] runs - * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of - * private/public nonces. - * - All signers communicate their public nonces to each other (revealing your - * private nonce can lead to discovery of your private key, so it should be - * considered secret). - * - All signers combine all the public nonces they received (excluding their - * own) using secp256k1_ec_pubkey_combine to obtain an - * Rall[i] = sum(R[0..i-1,i+1..n]). - * - All signers produce a partial signature using - * secp256k1_schnorr_partial_sign, passing in their own private key x[i], - * their own private nonce k[i], and the sum of the others' public nonces - * Rall[i]. - * - All signers communicate their partial signatures to each other. - * - Someone combines all partial signatures using - * secp256k1_schnorr_partial_combine, to obtain a full signature. - * - The resulting signature is validatable using secp256k1_schnorr_verify, with - * public key equal to the result of secp256k1_ec_pubkey_combine of the - * signers' public keys (sum(Q[0..n])). - * - * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine - * function take their arguments in any order, and it is possible to - * pre-combine several inputs already with one call, and add more inputs later - * by calling the function again (they are commutative and associative). - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign( - const secp256k1_context* ctx, - unsigned char *sig64, - const unsigned char *msg32, - const unsigned char *sec32, - const secp256k1_pubkey *pubnonce_others, - const unsigned char *secnonce32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); - -/** Combine multiple Schnorr partial signatures. - * Returns: 1: the passed signatures were successfully combined. - * 0: the resulting signature is not valid (chance of 1 in 2^256) - * -1: some inputs were invalid, or the signatures were not created - * using the same set of nonces - * Args: ctx: pointer to a context object - * Out: sig64: pointer to a 64-byte array to place the combined signature - * (cannot be NULL) - * In: sig64sin: pointer to an array of n pointers to 64-byte input - * signatures - * n: the number of signatures to combine (at least 1) - */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine( - const secp256k1_context* ctx, - unsigned char *sig64, - const unsigned char * const * sig64sin, - size_t n -) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - -# ifdef __cplusplus -} -# endif - -#endif diff --git a/libsecp256k1.pc.in b/libsecp256k1.pc.in index 1c72dd000..a0d006f11 100644 --- a/libsecp256k1.pc.in +++ b/libsecp256k1.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: libsecp256k1 Description: Optimized C library for EC operations on curve secp256k1 -URL: https://github.com/bitcoin/secp256k1 +URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs.private: @SECP_LIBS@ diff --git a/sage/group_prover.sage b/sage/group_prover.sage new file mode 100644 index 000000000..ab580c5b2 --- /dev/null +++ b/sage/group_prover.sage @@ -0,0 +1,322 @@ +# This code supports verifying group implementations which have branches +# or conditional statements (like cmovs), by allowing each execution path +# to independently set assumptions on input or intermediary variables. +# +# The general approach is: +# * A constraint is a tuple of two sets of of symbolic expressions: +# the first of which are required to evaluate to zero, the second of which +# are required to evaluate to nonzero. +# - A constraint is said to be conflicting if any of its nonzero expressions +# is in the ideal with basis the zero expressions (in other words: when the +# zero expressions imply that one of the nonzero expressions are zero). +# * There is a list of laws that describe the intended behaviour, including +# laws for addition and doubling. Each law is called with the symbolic point +# coordinates as arguments, and returns: +# - A constraint describing the assumptions under which it is applicable, +# called "assumeLaw" +# - A constraint describing the requirements of the law, called "require" +# * Implementations are transliterated into functions that operate as well on +# algebraic input points, and are called once per combination of branches +# exectured. Each execution returns: +# - A constraint describing the assumptions this implementation requires +# (such as Z1=1), called "assumeFormula" +# - A constraint describing the assumptions this specific branch requires, +# but which is by construction guaranteed to cover the entire space by +# merging the results from all branches, called "assumeBranch" +# - The result of the computation +# * All combinations of laws with implementation branches are tried, and: +# - If the combination of assumeLaw, assumeFormula, and assumeBranch results +# in a conflict, it means this law does not apply to this branch, and it is +# skipped. +# - For others, we try to prove the require constraints hold, assuming the +# information in assumeLaw + assumeFormula + assumeBranch, and if this does +# not succeed, we fail. +# + To prove an expression is zero, we check whether it belongs to the +# ideal with the assumed zero expressions as basis. This test is exact. +# + To prove an expression is nonzero, we check whether each of its +# factors is contained in the set of nonzero assumptions' factors. +# This test is not exact, so various combinations of original and +# reduced expressions' factors are tried. +# - If we succeed, we print out the assumptions from assumeFormula that +# weren't implied by assumeLaw already. Those from assumeBranch are skipped, +# as we assume that all constraints in it are complementary with each other. +# +# Based on the sage verification scripts used in the Explicit-Formulas Database +# by Tanja Lange and others, see http://hyperelliptic.org/EFD + +class fastfrac: + """Fractions over rings.""" + + def __init__(self,R,top,bot=1): + """Construct a fractional, given a ring, a numerator, and denominator.""" + self.R = R + if parent(top) == ZZ or parent(top) == R: + self.top = R(top) + self.bot = R(bot) + elif top.__class__ == fastfrac: + self.top = top.top + self.bot = top.bot * bot + else: + self.top = R(numerator(top)) + self.bot = R(denominator(top)) * bot + + def iszero(self,I): + """Return whether this fraction is zero given an ideal.""" + return self.top in I and self.bot not in I + + def reduce(self,assumeZero): + zero = self.R.ideal(map(numerator, assumeZero)) + return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) + + def __add__(self,other): + """Add two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top + self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __sub__(self,other): + """Subtract two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top - self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __neg__(self): + """Return the negation of a fraction.""" + return fastfrac(self.R,-self.top,self.bot) + + def __mul__(self,other): + """Multiply two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.top,self.bot * other.bot) + return NotImplemented + + def __rmul__(self,other): + """Multiply something else with a fraction.""" + return self.__mul__(other) + + def __div__(self,other): + """Divide two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top,self.bot * other) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot,self.bot * other.top) + return NotImplemented + + def __pow__(self,other): + """Compute a power of a fraction.""" + if parent(other) == ZZ: + if other < 0: + # Negative powers require flipping top and bottom + return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) + else: + return fastfrac(self.R,self.top ^ other,self.bot ^ other) + return NotImplemented + + def __str__(self): + return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" + def __repr__(self): + return "%s" % self + + def numerator(self): + return self.top + +class constraints: + """A set of constraints, consisting of zero and nonzero expressions. + + Constraints can either be used to express knowledge or a requirement. + + Both the fields zero and nonzero are maps from expressions to description + strings. The expressions that are the keys in zero are required to be zero, + and the expressions that are the keys in nonzero are required to be nonzero. + + Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in + nonzero could be multiplied into a single key. This is often much less + efficient to work with though, so we keep them separate inside the + constraints. This allows higher-level code to do fast checks on the individual + nonzero elements, or combine them if needed for stronger checks. + + We can't multiply the different zero elements, as it would suffice for one of + the factors to be zero, instead of all of them. Instead, the zero elements are + typically combined into an ideal first. + """ + + def __init__(self, **kwargs): + if 'zero' in kwargs: + self.zero = dict(kwargs['zero']) + else: + self.zero = dict() + if 'nonzero' in kwargs: + self.nonzero = dict(kwargs['nonzero']) + else: + self.nonzero = dict() + + def negate(self): + return constraints(zero=self.nonzero, nonzero=self.zero) + + def __add__(self, other): + zero = self.zero.copy() + zero.update(other.zero) + nonzero = self.nonzero.copy() + nonzero.update(other.nonzero) + return constraints(zero=zero, nonzero=nonzero) + + def __str__(self): + return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) + + def __repr__(self): + return "%s" % self + + +def conflicts(R, con): + """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" + zero = R.ideal(map(numerator, con.zero)) + if 1 in zero: + return True + # First a cheap check whether any of the individual nonzero terms conflict on + # their own. + for nonzero in con.nonzero: + if nonzero.iszero(zero): + return True + # It can be the case that entries in the nonzero set do not individually + # conflict with the zero set, but their combination does. For example, knowing + # that either x or y is zero is equivalent to having x*y in the zero set. + # Having x or y individually in the nonzero set is not a conflict, but both + # simultaneously is, so that is the right thing to check for. + if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): + return True + return False + + +def get_nonzero_set(R, assume): + """Calculate a simple set of nonzero expressions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = set() + for nz in map(numerator, assume.nonzero): + for (f,n) in nz.factor(): + nonzero.add(f) + rnz = zero.reduce(nz) + for (f,n) in rnz.factor(): + nonzero.add(f) + return nonzero + + +def prove_nonzero(R, exprs, assume): + """Check whether an expression is provably nonzero, given assumptions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = get_nonzero_set(R, assume) + expl = set() + ok = True + for expr in exprs: + if numerator(expr) in zero: + return (False, [exprs[expr]]) + allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) + for (f, n) in allexprs.factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for (f, n) in zero.reduce(numerator(allexprs)).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in numerator(expr).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in zero.reduce(numerator(expr)).factor(): + if f not in nonzero: + expl.add(exprs[expr]) + if expl: + return (False, list(expl)) + else: + return (True, None) + + +def prove_zero(R, exprs, assume): + """Check whether all of the passed expressions are provably zero, given assumptions""" + r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) + if not r: + return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) + zero = R.ideal(map(numerator, assume.zero)) + nonzero = prod(x for x in assume.nonzero) + expl = [] + for expr in exprs: + if not expr.iszero(zero): + expl.append(exprs[expr]) + if not expl: + return (True, None) + return (False, expl) + + +def describe_extra(R, assume, assumeExtra): + """Describe what assumptions are added, given existing assumptions""" + zerox = assume.zero.copy() + zerox.update(assumeExtra.zero) + zero = R.ideal(map(numerator, assume.zero)) + zeroextra = R.ideal(map(numerator, zerox)) + nonzero = get_nonzero_set(R, assume) + ret = set() + # Iterate over the extra zero expressions + for base in assumeExtra.zero: + if base not in zero: + add = [] + for (f, n) in numerator(base).factor(): + if f not in nonzero: + add += ["%s" % f] + if add: + ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) + # Iterate over the extra nonzero expressions + for nz in assumeExtra.nonzero: + nzr = zeroextra.reduce(numerator(nz)) + if nzr not in zeroextra: + for (f,n) in nzr.factor(): + if zeroextra.reduce(f) not in nonzero: + ret.add("%s != 0" % zeroextra.reduce(f)) + return ", ".join(x for x in ret) + + +def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): + """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" + assume = assumeLaw + assumeAssert + assumeBranch + + if conflicts(R, assume): + # This formula does not apply + return None + + describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + + ok, msg = prove_zero(R, require.zero, assume) + if not ok: + return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + + res, expl = prove_nonzero(R, require.nonzero, assume) + if not res: + return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + + if describe != "": + return "OK (assuming %s)" % describe + else: + return "OK" + + +def concrete_verify(c): + for k in c.zero: + if k != 0: + return (False, c.zero[k]) + for k in c.nonzero: + if k == 0: + return (False, c.nonzero[k]) + return (True, None) diff --git a/sage/secp256k1.sage b/sage/secp256k1.sage new file mode 100644 index 000000000..a97e732f7 --- /dev/null +++ b/sage/secp256k1.sage @@ -0,0 +1,306 @@ +# Test libsecp256k1' group operation implementations using prover.sage + +import sys + +load("group_prover.sage") +load("weierstrass_prover.sage") + +def formula_secp256k1_gej_double_var(a): + """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" + rz = a.Z * a.Y + rz = rz * 2 + t1 = a.X^2 + t1 = t1 * 3 + t2 = t1^2 + t3 = a.Y^2 + t3 = t3 * 2 + t4 = t3^2 + t4 = t4 * 2 + t3 = t3 * a.X + rx = t3 + rx = rx * 4 + rx = -rx + rx = rx + t2 + t2 = -t2 + t3 = t3 * 6 + t3 = t3 + t2 + ry = t1 * t3 + t2 = -t4 + ry = ry + t2 + return jacobianpoint(rx, ry, rz) + +def formula_secp256k1_gej_add_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_var""" + if branch == 0: + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z22 = b.Z^2 + z12 = a.Z^2 + u1 = a.X * z22 + u2 = b.X * z12 + s1 = a.Y * z22 + s1 = s1 * b.Z + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) + if branch == 3: + return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h2 * h + h = h * b.Z + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" + if branch == 0: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z12 = a.Z^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if (branch == 2): + r = formula_secp256k1_gej_double_var(a) + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if (branch == 3): + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_zinv_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_zinv_var""" + bzinv = b.Z^(-1) + if branch == 0: + return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) + if branch == 1: + bzinv2 = bzinv^2 + bzinv3 = bzinv2 * bzinv + rx = b.X * bzinv2 + ry = b.Y * bzinv3 + rz = 1 + return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + azz = a.Z * bzinv + z12 = azz^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * azz + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if branch == 3: + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z + rz = rz * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge""" + zeroes = {} + nonzeroes = {} + a_infinity = False + if (branch & 4) != 0: + nonzeroes.update({a.Infinity : 'a_infinite'}) + a_infinity = True + else: + zeroes.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + rr = t^2 + m_alt = -u2 + tt = u1 * m_alt + rr = rr + tt + degenerate = (branch & 3) == 3 + if (branch & 1) != 0: + zeroes.update({m : 'm_zero'}) + else: + nonzeroes.update({m : 'm_nonzero'}) + if (branch & 2) != 0: + zeroes.update({rr : 'rr_zero'}) + else: + nonzeroes.update({rr : 'rr_nonzero'}) + rr_alt = s1 + rr_alt = rr_alt * 2 + m_alt = m_alt + u1 + if not degenerate: + rr_alt = rr + m_alt = m + n = m_alt^2 + q = n * t + n = n^2 + if degenerate: + n = m + t = rr_alt^2 + rz = a.Z * m_alt + infinity = False + if (branch & 8) != 0: + if not a_infinity: + infinity = True + zeroes.update({rz : 'r.z=0'}) + else: + nonzeroes.update({rz : 'r.z!=0'}) + rz = rz * 2 + q = -q + t = t + q + rx = t + t = t * 2 + t = t + q + t = t * rr_alt + t = t + n + ry = -t + rx = rx * 4 + ry = ry * 4 + if a_infinity: + rx = b.X + ry = b.Y + rz = 1 + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_old(branch, a, b): + """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" + a_infinity = (branch & 1) != 0 + zero = {} + nonzero = {} + if a_infinity: + nonzero.update({a.Infinity : 'a_infinite'}) + else: + zero.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + z = a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + n = m^2 + q = n * t + n = n^2 + rr = t^2 + t = u1 * u2 + t = -t + rr = rr + t + t = rr^2 + rz = m * z + infinity = False + if (branch & 2) != 0: + if not a_infinity: + infinity = True + else: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) + zero.update({rz : 'r.z=0'}) + else: + nonzero.update({rz : 'r.z!=0'}) + rz = rz * (0 if a_infinity else 2) + rx = t + q = -q + rx = rx + q + q = q * 3 + t = t * 2 + t = t + q + t = t * rr + t = t + n + ry = -t + rx = rx * (0 if a_infinity else 4) + ry = ry * (0 if a_infinity else 4) + t = b.X + t = t * (1 if a_infinity else 0) + rx = rx + t + t = b.Y + t = t * (1 if a_infinity else 0) + ry = ry + t + t = (1 if a_infinity else 0) + rz = rz + t + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) + +if __name__ == "__main__": + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) + + if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) diff --git a/sage/weierstrass_prover.sage b/sage/weierstrass_prover.sage new file mode 100644 index 000000000..03ef2ec90 --- /dev/null +++ b/sage/weierstrass_prover.sage @@ -0,0 +1,264 @@ +# Prover implementation for Weierstrass curves of the form +# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws +# operating on affine and Jacobian coordinates, including the point at infinity +# represented by a 4th variable in coordinates. + +load("group_prover.sage") + + +class affinepoint: + def __init__(self, x, y, infinity=0): + self.x = x + self.y = y + self.infinity = infinity + def __str__(self): + return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) + + +class jacobianpoint: + def __init__(self, x, y, z, infinity=0): + self.X = x + self.Y = y + self.Z = z + self.Infinity = infinity + def __str__(self): + return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) + + +def point_at_infinity(): + return jacobianpoint(1, 1, 1, 1) + + +def negate(p): + if p.__class__ == affinepoint: + return affinepoint(p.x, -p.y) + if p.__class__ == jacobianpoint: + return jacobianpoint(p.X, -p.Y, p.Z) + assert(False) + + +def on_weierstrass_curve(A, B, p): + """Return a set of zero-expressions for an affine point to be on the curve""" + return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) + + +def tangential_to_weierstrass_curve(A, B, p12, p3): + """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" + return constraints(zero={ + (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' + }) + + +def colinear(p1, p2, p3): + """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" + return constraints(zero={ + (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', + (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', + (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' + }) + + +def good_affine_point(p): + return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) + + +def good_jacobian_point(p): + return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) + + +def good_point(p): + return constraints(nonzero={p.Z^6 : 'nonzero_X'}) + + +def finite(p, *affine_fns): + con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) + if p.Z != 0: + return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) + else: + return con + +def infinite(p): + return constraints(nonzero={p.Infinity : 'infinite_point'}) + + +def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(nonzero={pa.x - pb.x : 'different_x'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + colinear(pa, pb, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) + require = infinite(pC) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pb) + + infinite(pA) + + finite(pB)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + infinite(pB) + + finite(pA)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + infinite(pA) + + infinite(pB)) + require = infinite(pC) + return (assumeLaw, require) + + +laws_jacobian_weierstrass = { + 'add': law_jacobian_weierstrass_add, + 'double': law_jacobian_weierstrass_double, + 'add_opposite': law_jacobian_weierstrass_add_opposites, + 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, + 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, + 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab +} + + +def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" + F = Integers(p) + print "Formula %s on Z%i:" % (name, p) + points = [] + for x in xrange(0, p): + for y in xrange(0, p): + point = affinepoint(F(x), F(y)) + r, e = concrete_verify(on_weierstrass_curve(A, B, point)) + if r: + points.append(point) + + for za in xrange(1, p): + for zb in xrange(1, p): + for pa in points: + for pb in points: + for ia in xrange(2): + for ib in xrange(2): + pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) + pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) + for branch in xrange(0, branches): + assumeAssert, assumeBranch, pC = formula(branch, pA, pB) + pC.X = F(pC.X) + pC.Y = F(pC.Y) + pC.Z = F(pC.Z) + pC.Infinity = F(pC.Infinity) + r, e = concrete_verify(assumeAssert + assumeBranch) + if r: + match = False + for key in laws_jacobian_weierstrass: + assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) + r, e = concrete_verify(assumeLaw) + if r: + if match: + print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + else: + match = True + r, e = concrete_verify(require) + if not r: + print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) + print + + +def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): + assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) + return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) + +def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" + R. = PolynomialRing(QQ,8,order='invlex') + lift = lambda x: fastfrac(R,x) + ax = lift(ax) + ay = lift(ay) + Az = lift(Az) + bx = lift(bx) + by = lift(by) + Bz = lift(Bz) + Ai = lift(Ai) + Bi = lift(Bi) + + pa = affinepoint(ax, ay, Ai) + pb = affinepoint(bx, by, Bi) + pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) + pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) + + res = {} + + for key in laws_jacobian_weierstrass: + res[key] = [] + + print ("Formula " + name + ":") + count = 0 + for branch in xrange(branches): + assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + pC.X = lift(pC.X) + pC.Y = lift(pC.Y) + pC.Z = lift(pC.Z) + pC.Infinity = lift(pC.Infinity) + + for key in laws_jacobian_weierstrass: + res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + + for key in res: + print " %s:" % key + val = res[key] + for x in val: + if x[0] is not None: + print " branch %i: %s" % (x[1], x[0]) + + print diff --git a/src/asm/field_10x26_arm.s b/src/asm/field_10x26_arm.s new file mode 100644 index 000000000..5df561f2f --- /dev/null +++ b/src/asm/field_10x26_arm.s @@ -0,0 +1,919 @@ +@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: +/********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +/* +ARM implementation of field_10x26 inner loops. + +Note: + +- To avoid unnecessary loads and make use of available registers, two + 'passes' have every time been interleaved, with the odd passes accumulating c' and d' + which will be added to c and d respectively in the the even passes + +*/ + + .syntax unified + .arch armv7-a + @ eabi attributes - see readelf -A + .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes + .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no + .eabi_attribute 10, 0 @ Tag_FP_arch = none + .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte + .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed + .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 + .text + + @ Field constants + .set field_R0, 0x3d10 + .set field_R1, 0x400 + .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff + + .align 2 + .global secp256k1_fe_mul_inner + .type secp256k1_fe_mul_inner, %function + @ Arguments: + @ r0 r Restrict: can overlap with a, not with b + @ r1 a + @ r2 b + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_mul_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r7,r8 scratch + r1 a (pointer) + r2 b (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + + /* A - interleaved with B */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #9*4] @ b[9] + ldr r0, [r1, #1*4] @ a[1] + umull r5, r6, r7, r8 @ d = a[0] * b[9] + ldr r14, [r2, #8*4] @ b[8] + umull r9, r10, r0, r8 @ d' = a[1] * b[9] + ldr r7, [r1, #2*4] @ a[2] + umlal r5, r6, r0, r14 @ d += a[1] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r14 @ d' += a[2] * b[8] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r8 @ d += a[2] * b[7] + ldr r14, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r8 @ d' += a[3] * b[7] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r14 @ d += a[3] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r14 @ d' += a[4] * b[6] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r8 @ d += a[4] * b[5] + ldr r14, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r8 @ d' += a[5] * b[5] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r14 @ d += a[5] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r14 @ d' += a[6] * b[4] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[3] + ldr r14, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r8 @ d' += a[7] * b[3] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[7] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r9, r10, r7, r14 @ d' += a[8] * b[2] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r8 @ d += a[8] * b[1] + ldr r14, [r2, #0*4] @ b[0] + umlal r9, r10, r0, r8 @ d' += a[9] * b[1] + ldr r7, [r1, #0*4] @ a[0] + umlal r5, r6, r0, r14 @ d += a[9] * b[0] + @ r7,r14 used in B + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 4*9] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + umull r3, r4, r7, r14 @ c = a[0] * b[0] + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C - interleaved with D */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #2*4] @ b[2] + ldr r14, [r2, #1*4] @ b[1] + umull r11, r12, r7, r8 @ c' = a[0] * b[2] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[1] * b[1] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[2] * b[0] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r14 @ d += a[2] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[3] * b[9] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r8 @ d += a[3] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[4] * b[8] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r14 @ d += a[4] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[5] * b[7] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r8 @ d += a[5] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r8 @ d' += a[6] * b[6] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r14 @ d' += a[7] * b[5] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r8 @ d' += a[8] * b[4] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r14 @ d' += a[9] * b[3] + umlal r5, r6, r0, r8 @ d += a[9] * b[2] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E - interleaved with F */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #4*4] @ b[4] + umull r11, r12, r7, r8 @ c' = a[0] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r3, r4, r7, r8 @ c += a[0] * b[3] + ldr r7, [r1, #1*4] @ a[1] + umlal r11, r12, r7, r8 @ c' += a[1] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r3, r4, r7, r8 @ c += a[1] * b[2] + ldr r7, [r1, #2*4] @ a[2] + umlal r11, r12, r7, r8 @ c' += a[2] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r3, r4, r7, r8 @ c += a[2] * b[1] + ldr r7, [r1, #3*4] @ a[3] + umlal r11, r12, r7, r8 @ c' += a[3] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r3, r4, r7, r8 @ c += a[3] * b[0] + ldr r7, [r1, #4*4] @ a[4] + umlal r11, r12, r7, r8 @ c' += a[4] * b[0] + ldr r8, [r2, #9*4] @ b[9] + umlal r5, r6, r7, r8 @ d += a[4] * b[9] + ldr r7, [r1, #5*4] @ a[5] + umull r9, r10, r7, r8 @ d' = a[5] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umlal r5, r6, r7, r8 @ d += a[5] * b[8] + ldr r7, [r1, #6*4] @ a[6] + umlal r9, r10, r7, r8 @ d' += a[6] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[7] + ldr r7, [r1, #7*4] @ a[7] + umlal r9, r10, r7, r8 @ d' += a[7] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r5, r6, r7, r8 @ d += a[7] * b[6] + ldr r7, [r1, #8*4] @ a[8] + umlal r9, r10, r7, r8 @ d' += a[8] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r5, r6, r7, r8 @ d += a[8] * b[5] + ldr r7, [r1, #9*4] @ a[9] + umlal r9, r10, r7, r8 @ d' += a[9] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r5, r6, r7, r8 @ d += a[9] * b[4] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G - interleaved with H */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #6*4] @ b[6] + ldr r14, [r2, #5*4] @ b[5] + umull r11, r12, r7, r8 @ c' = a[0] * b[6] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[1] * b[5] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[2] * b[4] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[3] * b[3] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[4] * b[2] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[5] * b[1] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[6] * b[0] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[7] * b[9] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[8] * b[8] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[9] * b[7] + umlal r5, r6, r0, r8 @ d += a[9] * b[6] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I - interleaved with J */ + ldr r8, [r2, #8*4] @ b[8] + ldr r7, [r1, #0*4] @ a[0] + ldr r14, [r2, #7*4] @ b[7] + umull r11, r12, r7, r8 @ c' = a[0] * b[8] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r11, r12, r0, r14 @ c' += a[1] * b[7] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r11, r12, r7, r8 @ c' += a[2] * b[6] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[3] * b[5] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[4] * b[4] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[5] * b[3] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[6] * b[2] + ldr r0, [r1, #7*4] @ a[7] + umlal r3, r4, r7, r14 @ c += a[6] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[7] * b[1] + ldr r7, [r1, #8*4] @ a[8] + umlal r3, r4, r0, r8 @ c += a[7] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[8] * b[0] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[9] * b[9] + umlal r5, r6, r0, r8 @ d += a[9] * b[8] + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner + + .align 2 + .global secp256k1_fe_sqr_inner + .type secp256k1_fe_sqr_inner, %function + @ Arguments: + @ r0 r Can overlap with a + @ r1 a + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_sqr_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r2,r7,r8 scratch + r1 a (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + /* A interleaved with B */ + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r7, [r1, #0*4] @ a[0] + mov r0, r0, asl #1 + ldr r14, [r1, #9*4] @ a[9] + umull r3, r4, r7, r7 @ c = a[0] * a[0] + ldr r8, [r1, #8*4] @ a[8] + mov r7, r7, asl #1 + umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] + ldr r7, [r1, #2*4] @ a[2]*2 + umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #3*4] @ a[3]*2 + umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] + ldr r14, [r1, #5*4] @ a[5] + mov r7, r7, asl #1 + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] + umlal r9, r10, r14, r14 @ d' += a[5] * a[5] + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 9*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C interleaved with D */ + ldr r0, [r1, #0*4] @ a[0]*2 + ldr r14, [r1, #1*4] @ a[1] + mov r0, r0, asl #1 + ldr r8, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] + mov r7, r8, asl #1 @ a[2]*2 + umull r11, r12, r14, r14 @ c' = a[1] * a[1] + ldr r14, [r1, #9*4] @ a[9] + umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] + ldr r0, [r1, #3*4] @ a[3]*2 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] + umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] + umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] + umlal r9, r10, r8, r8 @ d' += a[6] * a[6] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E interleaved with F */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r14, [r1, #2*4] @ a[2] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + ldr r2, [r1, #4*4] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] + mov r2, r2, asl #1 @ a[4]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] + ldr r8, [r1, #9*4] @ a[9] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r11, r12, r14, r14 @ c' += a[2] * a[2] + ldr r14, [r1, #8*4] @ a[8] + mov r0, r0, asl #1 + umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] + ldr r7, [r1, #6*4] @ a[6]*2 + umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] + umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] + umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] + umlal r9, r10, r8, r8 @ d' += a[7] * a[7] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G interleaved with H */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #5*4] @ a[5] + ldr r2, [r1, #6*4] @ a[6] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] + mov r0, r2, asl #1 @ a[6]*2 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] + ldr r14, [r1, #9*4] @ a[9] + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] + ldr r7, [r1, #7*4] @ a[7]*2 + umlal r11, r12, r8, r8 @ c' += a[3] * a[3] + mov r7, r7, asl #1 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] + umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] + umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] + umlal r9, r10, r8, r8 @ d' += a[8] * a[8] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I interleaved with J */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + ldr r2, [r1, #8*4] @ a[8] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] + ldr r14, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] + ldr r8, [r1, #5*4] @ a[5] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] + ldr r0, [r1, #3*4] @ a[3]*2 + mov r7, r7, asl #1 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] + mov r2, r2, asl #1 @ a[8]*2 + umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] + umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] + umlal r11, r12, r14, r14 @ c' += a[4] * a[4] + ldr r8, [r1, #9*4] @ a[9] + umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] + @ r8 will be used in J + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + umlal r5, r6, r8, r8 @ d += a[9] * a[9] + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + diff --git a/src/bench_ecdh.c b/src/bench_ecdh.c index 5a7c6376e..cde5e2dbb 100644 --- a/src/bench_ecdh.c +++ b/src/bench_ecdh.c @@ -28,7 +28,8 @@ static void bench_ecdh_setup(void* arg) { 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f }; - data->ctx = secp256k1_context_create(0); + /* create a context with no capabilities */ + data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); for (i = 0; i < 32; i++) { data->scalar[i] = i + 1; } diff --git a/src/bench_internal.c b/src/bench_internal.c index 7809f5f8c..0809f77bd 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -181,12 +181,12 @@ void bench_field_inverse_var(void* arg) { } } -void bench_field_sqrt_var(void* arg) { +void bench_field_sqrt(void* arg) { int i; bench_inv_t *data = (bench_inv_t*)arg; for (i = 0; i < 20000; i++) { - secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x); + secp256k1_fe_sqrt(&data->fe_x, &data->fe_x); secp256k1_fe_add(&data->fe_x, &data->fe_y); } } @@ -227,6 +227,15 @@ void bench_group_add_affine_var(void* arg) { } } +void bench_group_jacobi_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_gej_has_quad_y_var(&data->gej_x); + } +} + void bench_ecmult_wnaf(void* arg) { int i; bench_inv_t *data = (bench_inv_t*)arg; @@ -299,6 +308,21 @@ void bench_context_sign(void* arg) { } } +#ifndef USE_NUM_NONE +void bench_num_jacobi(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_num nx, norder; + + secp256k1_scalar_get_num(&nx, &data->scalar_x); + secp256k1_scalar_order_get_num(&norder); + secp256k1_scalar_get_num(&norder, &data->scalar_y); + + for (i = 0; i < 200000; i++) { + secp256k1_num_jacobi(&nx, &norder); + } +} +#endif int have_flag(int argc, char** argv, char *flag) { char** argm = argv + argc; @@ -333,12 +357,13 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); @@ -350,5 +375,8 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); +#ifndef USE_NUM_NONE + if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000); +#endif return 0; } diff --git a/src/bench_verify.c b/src/bench_verify.c index 5718320cd..418defa0a 100644 --- a/src/bench_verify.c +++ b/src/bench_verify.c @@ -11,6 +11,12 @@ #include "util.h" #include "bench.h" +#ifdef ENABLE_OPENSSL_TESTS +#include +#include +#include +#endif + typedef struct { secp256k1_context *ctx; unsigned char msg[32]; @@ -19,6 +25,9 @@ typedef struct { size_t siglen; unsigned char pubkey[33]; size_t pubkeylen; +#ifdef ENABLE_OPENSSL_TESTS + EC_GROUP* ec_group; +#endif } benchmark_verify_t; static void benchmark_verify(void* arg) { @@ -40,6 +49,36 @@ static void benchmark_verify(void* arg) { } } +#ifdef ENABLE_OPENSSL_TESTS +static void benchmark_verify_openssl(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + { + EC_KEY *pkey = EC_KEY_new(); + const unsigned char *pubkey = &data->pubkey[0]; + int result; + + CHECK(pkey != NULL); + result = EC_KEY_set_group(pkey, data->ec_group); + CHECK(result); + result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL; + CHECK(result); + result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0); + CHECK(result); + EC_KEY_free(pkey); + } + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} +#endif + int main(void) { int i; secp256k1_pubkey pubkey; @@ -62,6 +101,11 @@ int main(void) { CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); +#ifdef ENABLE_OPENSSL_TESTS + data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1); + run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); + EC_GROUP_free(data.ec_group); +#endif secp256k1_context_destroy(data.ctx); return 0; diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h index d110b4bb1..9a42e519b 100644 --- a/src/ecdsa_impl.h +++ b/src/ecdsa_impl.h @@ -203,7 +203,9 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { unsigned char c[32]; secp256k1_scalar sn, u1, u2; +#if !defined(EXHAUSTIVE_TEST_ORDER) secp256k1_fe xr; +#endif secp256k1_gej pubkeyj; secp256k1_gej pr; @@ -219,6 +221,21 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const if (secp256k1_gej_is_infinity(&pr)) { return 0; } + +#if defined(EXHAUSTIVE_TEST_ORDER) +{ + secp256k1_scalar computed_r; + int overflow = 0; + secp256k1_ge pr_ge; + secp256k1_ge_set_gej(&pr_ge, &pr); + secp256k1_fe_normalize(&pr_ge.x); + + secp256k1_fe_get_b32(c, &pr_ge.x); + secp256k1_scalar_set_b32(&computed_r, c, &overflow); + /* we fully expect overflow */ + return secp256k1_scalar_eq(sigr, &computed_r); +} +#else secp256k1_scalar_get_b32(c, sigr); secp256k1_fe_set_b32(&xr, c); @@ -252,6 +269,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const return 1; } return 0; +#endif } static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index 90ac94770..0db314c48 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -58,25 +58,27 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { int global_sign; int skew = 0; int word = 0; + /* 1 2 3 */ int u_last; int u; -#ifdef USE_ENDOMORPHISM int flip; int bit; secp256k1_scalar neg_s; int not_neg_one; - /* If we are using the endomorphism, we cannot handle even numbers by negating - * them, since we are working with 128-bit numbers whose negations would be 256 - * bits, eliminating the performance advantage. Instead we use a technique from + /* Note that we cannot handle even numbers by negating them to be odd, as is + * done in other implementations, since if our scalars were specified to have + * width < 256 for performance reasons, their negations would have width 256 + * and we'd lose any performance benefit. Instead, we use a technique from * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) - * or 2 (for odd) to the number we are encoding, then compensating after the - * multiplication. */ - /* Negative 128-bit numbers will be negated, since otherwise they are 256-bit */ + * or 2 (for odd) to the number we are encoding, returning a skew value indicating + * this, and having the caller compensate after doing the multiplication. */ + + /* Negative numbers will be negated to keep their bit representation below the maximum width */ flip = secp256k1_scalar_is_high(&s); /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ - bit = flip ^ (s.d[0] & 1); + bit = flip ^ !secp256k1_scalar_is_even(&s); /* We check for negative one, since adding 2 to it will cause an overflow */ secp256k1_scalar_negate(&neg_s, &s); not_neg_one = !secp256k1_scalar_is_one(&neg_s); @@ -89,11 +91,6 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { global_sign = secp256k1_scalar_cond_negate(&s, flip); global_sign *= not_neg_one * 2 - 1; skew = 1 << bit; -#else - /* Otherwise, we just negate to force oddness */ - int is_even = secp256k1_scalar_is_even(&s); - global_sign = secp256k1_scalar_cond_negate(&s, is_even); -#endif /* 4 */ u_last = secp256k1_scalar_shr_int(&s, w); @@ -127,15 +124,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons secp256k1_ge tmpa; secp256k1_fe Z; + int skew_1; + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; #ifdef USE_ENDOMORPHISM secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; - int skew_1; int skew_lam; secp256k1_scalar q_1, q_lam; -#else - int wnaf[1 + WNAF_SIZE(WINDOW_A - 1)]; #endif int i; @@ -145,18 +140,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons #ifdef USE_ENDOMORPHISM /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); - /* no need for zero correction when using endomorphism since even - * numbers have one added to them anyway */ skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); #else - int is_zero = secp256k1_scalar_is_zero(scalar); - /* the wNAF ladder cannot handle zero, so bump this to one .. we will - * correct the result after the fact */ - sc.d[0] += is_zero; - VERIFY_CHECK(!secp256k1_scalar_is_zero(&sc)); - - secp256k1_wnaf_const(wnaf, sc, WINDOW_A - 1); + skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1); #endif /* Calculate odd multiples of a. @@ -179,21 +166,15 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons /* first loop iteration (separated out so we can directly set r, rather * than having it start at infinity, get doubled several times, then have * its new value added to it) */ -#ifdef USE_ENDOMORPHISM i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; VERIFY_CHECK(i != 0); ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); secp256k1_gej_set_ge(r, &tmpa); - +#ifdef USE_ENDOMORPHISM i = wnaf_lam[WNAF_SIZE(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); -#else - i = wnaf[WNAF_SIZE(WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); - secp256k1_gej_set_ge(r, &tmpa); #endif /* remaining loop iterations */ for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { @@ -202,59 +183,57 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons for (j = 0; j < WINDOW_A - 1; ++j) { secp256k1_gej_double_nonzero(r, r, NULL); } -#ifdef USE_ENDOMORPHISM + n = wnaf_1[i]; 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 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); -#else - n = wnaf[i]; - VERIFY_CHECK(n != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - secp256k1_gej_add_ge(r, r, &tmpa); #endif } secp256k1_fe_mul(&r->z, &r->z, &Z); -#ifdef USE_ENDOMORPHISM { /* 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 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 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 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); - } -#else - /* correct for zero */ - r->infinity |= is_zero; #endif + } } #endif diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index b63c4d866..35f254607 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -77,7 +77,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); } } - secp256k1_ge_set_all_gej_var(1024, prec, precj, cb); + secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb); } for (j = 0; j < 64; j++) { for (i = 0; i < 16; i++) { diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index e6e5f4718..4e40104ad 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -7,13 +7,29 @@ #ifndef _SECP256K1_ECMULT_IMPL_H_ #define _SECP256K1_ECMULT_IMPL_H_ +#include + #include "group.h" #include "scalar.h" #include "ecmult.h" +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to lower these values for exhaustive tests because + * the tables cannot have infinities in them (this breaks the + * affine-isomorphism stuff which tracks z-ratios) */ +# if EXHAUSTIVE_TEST_ORDER > 128 +# define WINDOW_A 5 +# define WINDOW_G 8 +# elif EXHAUSTIVE_TEST_ORDER > 8 +# define WINDOW_A 4 +# define WINDOW_G 4 +# else +# define WINDOW_A 2 +# define WINDOW_G 2 +# endif +#else /* optimal for 128-bit and 256-bit exponents. */ #define WINDOW_A 5 - /** larger numbers may result in slightly better performance, at the cost of exponentially larger precomputed tables. */ #ifdef USE_ENDOMORPHISM @@ -23,6 +39,7 @@ /** One table for window size 16: 1.375 MiB. */ #define WINDOW_G 16 #endif +#endif /** The number of entries a table with precomputed multiples needs to have. */ #define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) @@ -101,7 +118,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge /* Compute the odd multiples in Jacobian form. */ secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); /* Convert them in batch to affine coordinates. */ - secp256k1_ge_set_table_gej_var(n, prea, prej, zr); + secp256k1_ge_set_table_gej_var(prea, prej, zr, n); /* Convert them to compact storage form. */ for (i = 0; i < n; i++) { secp256k1_ge_to_storage(&pre[i], &prea[i]); diff --git a/src/field.h b/src/field.h index 2d52af5e3..bbb1ee866 100644 --- a/src/field.h +++ b/src/field.h @@ -30,6 +30,8 @@ #error "Please select field implementation" #endif +#include "util.h" + /** Normalize a field element. */ static void secp256k1_fe_normalize(secp256k1_fe *r); @@ -50,6 +52,9 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); /** Set a field element equal to a small integer. Resulting field element is normalized. */ static void secp256k1_fe_set_int(secp256k1_fe *r, int a); +/** Sets a field element equal to zero, initializing all fields. */ +static void secp256k1_fe_clear(secp256k1_fe *a); + /** Verify whether a field element is zero. Requires the input to be normalized. */ static int secp256k1_fe_is_zero(const secp256k1_fe *a); @@ -57,6 +62,9 @@ static int secp256k1_fe_is_zero(const secp256k1_fe *a); static int secp256k1_fe_is_odd(const secp256k1_fe *a); /** Compare two field elements. Requires magnitude-1 inputs. */ +static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Same as secp256k1_fe_equal, but may be variable time. */ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ @@ -92,7 +100,10 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); * The input's magnitude can be at most 8. The output magnitude is 1 (but not * guaranteed to be normalized). The result in r will always be a square * itself. */ -static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a); +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); + +/** Checks whether a field element is a quadratic residue. */ +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a); /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ @@ -104,7 +115,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); /** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and * outputs must not overlap in memory. */ -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a); +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len); /** Convert a field element to the storage type. */ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 212cc5396..7b8c07960 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -7,8 +7,6 @@ #ifndef _SECP256K1_FIELD_REPR_IMPL_H_ #define _SECP256K1_FIELD_REPR_IMPL_H_ -#include -#include #include "util.h" #include "num.h" #include "field.h" @@ -429,6 +427,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f #endif } +#if defined(USE_EXTERNAL_ASM) + +/* External assembler implementation */ +void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); +void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); + +#else + #ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) #else @@ -1037,7 +1043,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t VERIFY_BITS(r[2], 27); /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } - +#endif static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index b31e24ab8..7a99eb21e 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -11,7 +11,6 @@ #include "libsecp256k1-config.h" #endif -#include #include "util.h" #include "num.h" #include "field.h" diff --git a/src/field_5x52_int128_impl.h b/src/field_5x52_int128_impl.h index 9280bb5ea..0bf22bdd3 100644 --- a/src/field_5x52_int128_impl.h +++ b/src/field_5x52_int128_impl.h @@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t VERIFY_BITS(r[2], 52); VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; @@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; diff --git a/src/field_impl.h b/src/field_impl.h index 77f4aae2f..5127b279b 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -21,6 +21,13 @@ #error "Please select field implementation" #endif +SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero(&na); +} + SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe na; secp256k1_fe_negate(&na, a, 1); @@ -28,7 +35,7 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const return secp256k1_fe_normalizes_to_zero_var(&na); } -static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) { +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { /** Given that p is congruent to 3 mod 4, we can compute the square root of * a mod p as the (p+1)/4'th power of a. * @@ -123,7 +130,7 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - return secp256k1_fe_equal_var(&t1, a); + return secp256k1_fe_equal(&t1, a); } static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { @@ -253,7 +260,7 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { #endif } -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) { +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) { secp256k1_fe u; size_t i; if (len < 1) { @@ -280,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k r[0] = u; } +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) { +#ifndef USE_NUM_NONE + unsigned char b[32]; + secp256k1_num n; + secp256k1_num m; + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 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 + }; + + secp256k1_fe c = *a; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_set_bin(&m, prime, 32); + return secp256k1_num_jacobi(&n, &m) >= 0; +#else + secp256k1_fe r; + return secp256k1_fe_sqrt(&r, a); +#endif +} + #endif diff --git a/src/group.h b/src/group.h index ebfe1ca70..4957b248f 100644 --- a/src/group.h +++ b/src/group.h @@ -47,7 +47,7 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se * and a Y coordinate that is a quadratic residue modulo p. The return value * is true iff a coordinate with the given X coordinate exists. */ -static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x); +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x); /** Set a group element (affine) equal to the point with the given X coordinate, and given oddness * for Y. Return value indicates whether the result is valid. */ @@ -65,12 +65,12 @@ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); /** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb); +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb); /** Set a batch of group elements equal to the inputs given in jacobian * coordinates (with known z-ratios). zr must contain the known z-ratios such * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ -static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr); +static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len); /** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to * the same global z "denominator". zr must contain the known z-ratios such @@ -94,6 +94,9 @@ static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); /** Check whether a group element is the point at infinity. */ static int secp256k1_gej_is_infinity(const secp256k1_gej *a); +/** Check whether a group element's y coordinate is a quadratic residue. */ +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a); + /** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). * a may not be zero. Constant time. */ static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); diff --git a/src/group_impl.h b/src/group_impl.h index 42e2f6e6e..2e192b62f 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -7,12 +7,57 @@ #ifndef _SECP256K1_GROUP_IMPL_H_ #define _SECP256K1_GROUP_IMPL_H_ -#include - #include "num.h" #include "field.h" #include "group.h" +/* These points can be generated in sage as follows: + * + * 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() + */ +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 199 +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 +); + +const int CURVE_B = 4; +# elif EXHAUSTIVE_TEST_ORDER == 13 +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 +); +const int CURVE_B = 2; +# else +# error No known generator for the specified exhaustive test group order. +# endif +#else /** Generator for secp256k1, value 'g' defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ @@ -23,8 +68,11 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL ); +const int CURVE_B = 7; +#endif + static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { - secp256k1_fe zi2; + secp256k1_fe zi2; secp256k1_fe zi3; secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi); @@ -78,7 +126,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { r->y = a->y; } -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) { +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) { secp256k1_fe *az; secp256k1_fe *azi; size_t i; @@ -91,7 +139,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp } azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); - secp256k1_fe_inv_all_var(count, azi, az); + secp256k1_fe_inv_all_var(azi, az, count); free(az); count = 0; @@ -104,7 +152,7 @@ static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp free(azi); } -static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) { +static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) { size_t i = len - 1; secp256k1_fe zi; @@ -147,9 +195,15 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp static void secp256k1_gej_set_infinity(secp256k1_gej *r) { r->infinity = 1; - secp256k1_fe_set_int(&r->x, 0); - secp256k1_fe_set_int(&r->y, 0); - secp256k1_fe_set_int(&r->z, 0); + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); + secp256k1_fe_clear(&r->z); +} + +static void secp256k1_ge_set_infinity(secp256k1_ge *r) { + r->infinity = 1; + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); } static void secp256k1_gej_clear(secp256k1_gej *r) { @@ -165,19 +219,19 @@ static void secp256k1_ge_clear(secp256k1_ge *r) { secp256k1_fe_clear(&r->y); } -static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) { +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) { secp256k1_fe x2, x3, c; r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; - secp256k1_fe_set_int(&c, 7); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&c, &x3); - return secp256k1_fe_sqrt_var(&r->y, &c); + return secp256k1_fe_sqrt(&r->y, &c); } static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { - if (!secp256k1_ge_set_xquad_var(r, x)) { + if (!secp256k1_ge_set_xquad(r, x)) { return 0; } secp256k1_fe_normalize_var(&r->y); @@ -230,7 +284,7 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { 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, 7); + secp256k1_fe_mul_int(&z6, CURVE_B); secp256k1_fe_add(&x3, &z6); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); @@ -244,18 +298,30 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { /* 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, 7); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&x3, &c); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); } static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { - /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */ + /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate. + * + * Note that there is an implementation described at + * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + * which trades a multiply for a square, but in practice this is actually slower, + * mainly because it requires more normalizations. + */ secp256k1_fe t1,t2,t3,t4; /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). */ r->infinity = a->infinity; if (r->infinity) { @@ -623,4 +689,18 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { } #endif +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { + secp256k1_fe yz; + + if (a->infinity) { + return 0; + } + + /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as + * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z + is */ + secp256k1_fe_mul(&yz, &a->y, &a->z); + return secp256k1_fe_is_quad_var(&yz); +} + #endif diff --git a/src/hash.h b/src/hash.h index 0ff01e63f..fca98cab9 100644 --- a/src/hash.h +++ b/src/hash.h @@ -11,7 +11,7 @@ #include typedef struct { - uint32_t s[32]; + uint32_t s[8]; uint32_t buf[16]; /* In big endian */ size_t bytes; } secp256k1_sha256_t; diff --git a/src/hash_impl.h b/src/hash_impl.h index ae55df6d8..b47e65f83 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -269,15 +269,13 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 rng->retry = 0; } - +#undef BE32 #undef Round -#undef sigma0 #undef sigma1 -#undef Sigma0 +#undef sigma0 #undef Sigma1 -#undef Ch +#undef Sigma0 #undef Maj -#undef ReadBE32 -#undef WriteBE32 +#undef Ch #endif diff --git a/src/java/org/bitcoin/NativeSecp256k1.java b/src/java/org/bitcoin/NativeSecp256k1.java index 90a498eaa..1c67802fb 100644 --- a/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/java/org/bitcoin/NativeSecp256k1.java @@ -1,60 +1,446 @@ +/* + * Copyright 2013 Google Inc. + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.bitcoin; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.math.BigInteger; import com.google.common.base.Preconditions; - +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import static org.bitcoin.NativeSecp256k1Util.*; /** - * This class holds native methods to handle ECDSA verification. - * You can find an example library that can be used for this at - * https://github.com/sipa/secp256k1 + *

This class holds native methods to handle ECDSA verification.

+ * + *

You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1

+ * + *

To build secp256k1 for use with bitcoinj, run + * `./configure --enable-jni --enable-experimental --enable-module-ecdh` + * and `make` then copy `.libs/libsecp256k1.so` to your system library path + * or point the JVM to the folder containing it with -Djava.library.path + *

*/ public class NativeSecp256k1 { - public static final boolean enabled; - static { - boolean isEnabled = true; - try { - System.loadLibrary("javasecp256k1"); - } catch (UnsatisfiedLinkError e) { - isEnabled = false; - } - enabled = isEnabled; - } - + + private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private static final Lock r = rwl.readLock(); + private static final Lock w = rwl.writeLock(); private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); /** * Verifies the given secp256k1 signature in native code. * Calling when enabled == false is undefined (probably library not loaded) - * + * * @param data The data which was signed, must be exactly 32 bytes * @param signature The signature * @param pub The public key which did the signing */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub) { + public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); + if (byteBuff == null || byteBuff.capacity() < 520) { + byteBuff = ByteBuffer.allocateDirect(520); byteBuff.order(ByteOrder.nativeOrder()); nativeECDSABuffer.set(byteBuff); } byteBuff.rewind(); byteBuff.put(data); - byteBuff.putInt(signature.length); - byteBuff.putInt(pub.length); byteBuff.put(signature); byteBuff.put(pub); - return secp256k1_ecdsa_verify(byteBuff) == 1; + + byte[][] retByteArray; + + r.lock(); + try { + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; + } finally { + r.unlock(); + } + } + + /** + * libsecp256k1 Create an ECDSA signature. + * + * @param data Message hash, 32 bytes + * @param key Secret key, 32 bytes + * + * Return values + * @param sig byte array of signature + */ + public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && sec.length <= 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + 32) { + byteBuff = ByteBuffer.allocateDirect(32 + 32); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(sec); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] sigArr = retByteArray[0]; + int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(sigArr.length, sigLen, "Got bad signature length."); + + return retVal == 0 ? new byte[0] : sigArr; + } + + /** + * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid + * + * @param seckey ECDSA Secret key, 32 bytes + */ + public static boolean secKeyVerify(byte[] seckey) { + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + r.lock(); + try { + return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; + } finally { + r.unlock(); + } + } + + + /** + * libsecp256k1 Compute Pubkey - computes public key from secret key + * + * @param seckey ECDSA Secret key, 32 bytes + * + * Return values + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + //TODO add a 'compressed' arg + public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + return retVal == 0 ? new byte[0]: pubArr; + } + + /** + * libsecp256k1 Cleanup - This destroys the secp256k1 context object + * This should be called at the end of the program for proper cleanup of the context. + */ + public static synchronized void cleanup() { + w.lock(); + try { + secp256k1_destroy_context(Secp256k1Context.getContext()); + } finally { + w.unlock(); + } + } + + public static long cloneContext() { + r.lock(); + try { + return secp256k1_ctx_clone(Secp256k1Context.getContext()); + } finally { r.unlock(); } + } + + /** + * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; } /** - * @param byteBuff signature format is byte[32] data, - * native-endian int signatureLength, native-endian int pubkeyLength, - * byte[signatureLength] signature, byte[pubkeyLength] pub - * @returns 1 for valid signature, anything else for invalid + * libsecp256k1 create ECDH secret - constant time ECDH calculation + * + * @param seckey byte array of secret key used in exponentiaion + * @param pubkey byte array of public key used in exponentiaion */ - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); + public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { + byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + byteBuff.put(pubkey); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] resArr = retByteArray[0]; + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + + assertEquals(resArr.length, 32, "Got bad result length."); + assertEquals(retVal, 1, "Failed return value check."); + + return resArr; + } + + /** + * libsecp256k1 randomize - updates the context randomization + * + * @param seed 32-byte random seed + */ + public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ + Preconditions.checkArgument(seed.length == 32 || seed == null); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seed.length) { + byteBuff = ByteBuffer.allocateDirect(seed.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seed); + + w.lock(); + try { + return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; + } finally { + w.unlock(); + } + } + + private static native long secp256k1_ctx_clone(long context); + + private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); + + private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); + + private static native void secp256k1_destroy_context(long context); + + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); + + private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); + + private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + + private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); + } diff --git a/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/java/org/bitcoin/NativeSecp256k1Test.java new file mode 100644 index 000000000..c00d08899 --- /dev/null +++ b/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -0,0 +1,226 @@ +package org.bitcoin; + +import com.google.common.io.BaseEncoding; +import java.util.Arrays; +import java.math.BigInteger; +import javax.xml.bind.DatatypeConverter; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + * This class holds test cases defined for testing this library. + */ +public class NativeSecp256k1Test { + + //TODO improve comments/add more tests + /** + * This tests verify() for a valid signature + */ + public static void testVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + assertEquals( result, true , "testVerifyPos"); + } + + /** + * This tests verify() for a non-valid signature + */ + public static void testVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testVerifyNeg"); + } + + /** + * This tests secret key verify() for a valid secretkey + */ + public static void testSecKeyVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, true , "testSecKeyVerifyPos"); + } + + /** + * This tests secret key verify() for a invalid secretkey + */ + public static void testSecKeyVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testSecKeyVerifyNeg"); + } + + /** + * This tests public key create() for a valid secretkey + */ + public static void testPubKeyCreatePos() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); + } + + /** + * This tests public key create() for a invalid secretkey + */ + public static void testPubKeyCreateNeg() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); + } + + /** + * This tests sign() for a valid secretkey + */ + public static void testSignPos() throws AssertFailException{ + + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); + } + + /** + * This tests sign() for a invalid secretkey + */ + public static void testSignNeg() throws AssertFailException{ + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "" , "testSignNeg"); + } + + /** + * This tests private key tweak-add + */ + public static void testPrivKeyTweakAdd_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); + } + + /** + * This tests private key tweak-mul + */ + public static void testPrivKeyTweakMul_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); + } + + /** + * This tests private key tweak-add uncompressed + */ + public static void testPrivKeyTweakAdd_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); + } + + /** + * This tests private key tweak-mul uncompressed + */ + public static void testPrivKeyTweakMul_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); + } + + /** + * This tests seed randomization + */ + public static void testRandomize() throws AssertFailException { + byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" + boolean result = NativeSecp256k1.randomize(seed); + assertEquals( result, true, "testRandomize"); + } + + public static void testCreateECDHSecret() throws AssertFailException{ + + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); + String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); + } + + public static void main(String[] args) throws AssertFailException{ + + + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); + + assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); + + //Test verify() success/fail + testVerifyPos(); + testVerifyNeg(); + + //Test secKeyVerify() success/fail + testSecKeyVerifyPos(); + testSecKeyVerifyNeg(); + + //Test computePubkey() success/fail + testPubKeyCreatePos(); + testPubKeyCreateNeg(); + + //Test sign() success/fail + testSignPos(); + testSignNeg(); + + //Test privKeyTweakAdd() 1 + testPrivKeyTweakAdd_1(); + + //Test privKeyTweakMul() 2 + testPrivKeyTweakMul_1(); + + //Test privKeyTweakAdd() 3 + testPrivKeyTweakAdd_2(); + + //Test privKeyTweakMul() 4 + testPrivKeyTweakMul_2(); + + //Test randomize() + testRandomize(); + + //Test ECDH + testCreateECDHSecret(); + + NativeSecp256k1.cleanup(); + + System.out.println(" All tests passed." ); + + } +} diff --git a/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/java/org/bitcoin/NativeSecp256k1Util.java new file mode 100644 index 000000000..04732ba04 --- /dev/null +++ b/src/java/org/bitcoin/NativeSecp256k1Util.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +public class NativeSecp256k1Util{ + + public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + } + + public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ + if( !val.equals(val2) ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static class AssertFailException extends Exception { + public AssertFailException(String message) { + super( message ); + } + } +} diff --git a/src/java/org/bitcoin/Secp256k1Context.java b/src/java/org/bitcoin/Secp256k1Context.java new file mode 100644 index 000000000..216c986a8 --- /dev/null +++ b/src/java/org/bitcoin/Secp256k1Context.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoin; + +/** + * This class holds the context reference used in native methods + * to handle ECDSA operations. + */ +public class Secp256k1Context { + private static final boolean enabled; //true if the library is loaded + private static final long context; //ref to pointer to context obj + + static { //static initializer + boolean isEnabled = true; + long contextRef = -1; + try { + System.loadLibrary("secp256k1"); + contextRef = secp256k1_init_context(); + } catch (UnsatisfiedLinkError e) { + System.out.println("UnsatisfiedLinkError: " + e.toString()); + isEnabled = false; + } + enabled = isEnabled; + context = contextRef; + } + + public static boolean isEnabled() { + return enabled; + } + + public static long getContext() { + if(!enabled) return -1; //sanity check + return context; + } + + private static native long secp256k1_init_context(); +} diff --git a/src/java/org_bitcoin_NativeSecp256k1.c b/src/java/org_bitcoin_NativeSecp256k1.c index bb4cd7072..bcef7b32c 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,23 +1,377 @@ +#include +#include +#include #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "include/secp256k1_recovery.h" -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); + + (void)classObject;(void)env; + + return ctx_clone_l; + +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) { - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int sigLen = *((int*)(data + 32)); - int pubLen = *((int*)(data + 32 + 4)); + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_context_randomize(ctx, seed); - return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); } -static void __javasecp256k1_attach(void) __attribute__((constructor)); -static void __javasecp256k1_detach(void) __attribute__((destructor)); +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + secp256k1_context_destroy(ctx); -static void __javasecp256k1_attach(void) { - secp256k1_start(SECP256K1_START_VERIFY); + (void)classObject;(void)env; } -static void __javasecp256k1_detach(void) { - secp256k1_stop(); +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* sigdata = { (unsigned char*) (data + 32) }; + const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; + + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pubkey; + + int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); + + if( ret ) { + ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if( ret ) { + ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); + } + } + + (void)classObject; + + return ret; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[2]; + + secp256k1_ecdsa_signature sig[72]; + + int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); + + unsigned char outputSer[72]; + size_t outputLen = 72; + + if( ret ) { + int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + sigArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_ec_seckey_verify(ctx, secKey); +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + secp256k1_pubkey pubkey; + + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); + + unsigned char outputSer[65]; + size_t outputLen = 65; + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubkeyArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; + +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; +/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if( ret ) { + ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if ( ret ) { + ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) +{ + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; + + return 0; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* pubdata = (const unsigned char*) (secdata + 32); + + jobjectArray retArray; + jbyteArray outArray, intsByteArray; + unsigned char intsarray[1]; + secp256k1_pubkey pubkey; + unsigned char nonce_res[32]; + size_t outputLen = 32; + + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if (ret) { + ret = secp256k1_ecdh( + ctx, + nonce_res, + &pubkey, + secdata + ); + } + + intsarray[0] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + outArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); + (*env)->SetObjectArrayElement(env, retArray, 0, outArray); + + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; } diff --git a/src/java/org_bitcoin_NativeSecp256k1.h b/src/java/org_bitcoin_NativeSecp256k1.h index d7fb004fa..fe613c9e9 100644 --- a/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/java/org_bitcoin_NativeSecp256k1.h @@ -1,5 +1,6 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include +#include "include/secp256k1.h" /* Header for class org_bitcoin_NativeSecp256k1 */ #ifndef _Included_org_bitcoin_NativeSecp256k1 @@ -7,13 +8,110 @@ #ifdef __cplusplus extern "C" { #endif +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ctx_clone + * Signature: (J)J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_context_randomize + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_destroy_context + * Signature: (J)V + */ +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv *, jclass, jlong); + /* * Class: org_bitcoin_NativeSecp256k1 * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;)I + * Signature: (Ljava/nio/ByteBuffer;JII)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv *, jclass, jobject, jlong, jint, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_seckey_verify + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_create + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_parse + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdh + * Signature: (Ljava/nio/ByteBuffer;JI)[[B */ -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject); +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen); + #ifdef __cplusplus } diff --git a/src/java/org_bitcoin_Secp256k1Context.c b/src/java/org_bitcoin_Secp256k1Context.c new file mode 100644 index 000000000..a52939e7e --- /dev/null +++ b/src/java/org_bitcoin_Secp256k1Context.c @@ -0,0 +1,15 @@ +#include +#include +#include "org_bitcoin_Secp256k1Context.h" +#include "include/secp256k1.h" + +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (uintptr_t)ctx; +} + diff --git a/src/java/org_bitcoin_Secp256k1Context.h b/src/java/org_bitcoin_Secp256k1Context.h new file mode 100644 index 000000000..0d2bc84b7 --- /dev/null +++ b/src/java/org_bitcoin_Secp256k1Context.h @@ -0,0 +1,22 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_Secp256k1Context */ + +#ifndef _Included_org_bitcoin_Secp256k1Context +#define _Included_org_bitcoin_Secp256k1Context +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_Secp256k1Context + * Method: secp256k1_init_context + * Signature: ()J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/ecdh/Makefile.am.include b/src/modules/ecdh/Makefile.am.include index 670b9c115..e3088b469 100644 --- a/src/modules/ecdh/Makefile.am.include +++ b/src/modules/ecdh/Makefile.am.include @@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/ecdh/tests_impl.h if USE_BENCHMARK noinst_PROGRAMS += bench_ecdh bench_ecdh_SOURCES = src/bench_ecdh.c -bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) endif diff --git a/src/modules/recovery/Makefile.am.include b/src/modules/recovery/Makefile.am.include index 5de3ea33e..bf23c26e7 100644 --- a/src/modules/recovery/Makefile.am.include +++ b/src/modules/recovery/Makefile.am.include @@ -4,5 +4,5 @@ noinst_HEADERS += src/modules/recovery/tests_impl.h if USE_BENCHMARK noinst_PROGRAMS += bench_recover bench_recover_SOURCES = src/bench_recover.c -bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) endif diff --git a/src/modules/recovery/main_impl.h b/src/modules/recovery/main_impl.h old mode 100644 new mode 100755 index ec42f4bb6..86f2f0cb2 --- a/src/modules/recovery/main_impl.h +++ b/src/modules/recovery/main_impl.h @@ -138,16 +138,15 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; unsigned int count = 0; secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { - unsigned char nonce32[32]; ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); if (!secp256k1_scalar_is_zero(&non) && !overflow) { if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { break; @@ -155,6 +154,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd } count++; } + memset(nonce32, 0, 32); secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); diff --git a/src/modules/schnorr/Makefile.am.include b/src/modules/schnorr/Makefile.am.include deleted file mode 100644 index b3bfa7d5c..000000000 --- a/src/modules/schnorr/Makefile.am.include +++ /dev/null @@ -1,10 +0,0 @@ -include_HEADERS += include/secp256k1_schnorr.h -noinst_HEADERS += src/modules/schnorr/main_impl.h -noinst_HEADERS += src/modules/schnorr/schnorr.h -noinst_HEADERS += src/modules/schnorr/schnorr_impl.h -noinst_HEADERS += src/modules/schnorr/tests_impl.h -if USE_BENCHMARK -noinst_PROGRAMS += bench_schnorr_verify -bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c -bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -endif diff --git a/src/modules/schnorr/main_impl.h b/src/modules/schnorr/main_impl.h deleted file mode 100644 index fa176a176..000000000 --- a/src/modules/schnorr/main_impl.h +++ /dev/null @@ -1,164 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2015 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_SCHNORR_MAIN -#define SECP256K1_MODULE_SCHNORR_MAIN - -#include "include/secp256k1_schnorr.h" -#include "modules/schnorr/schnorr_impl.h" - -static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { - secp256k1_sha256_t sha; - secp256k1_sha256_initialize(&sha); - secp256k1_sha256_write(&sha, r32, 32); - secp256k1_sha256_write(&sha, msg32, 32); - secp256k1_sha256_finalize(&sha, h32); -} - -static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 "; - -int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { - secp256k1_scalar sec, non; - int ret = 0; - int overflow = 0; - unsigned int count = 0; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - secp256k1_scalar_set_b32(&sec, seckey, NULL); - while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) { - break; - } - } - count++; - } - if (!ret) { - memset(sig64, 0, 64); - } - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - return ret; -} - -int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { - secp256k1_ge q; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(pubkey != NULL); - - secp256k1_pubkey_load(ctx, &q, pubkey); - return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32); -} - -int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) { - secp256k1_ge q; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(pubkey != NULL); - - if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) { - secp256k1_pubkey_save(pubkey, &q); - return 1; - } else { - memset(pubkey, 0, sizeof(*pubkey)); - return 0; - } -} - -int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) { - int count = 0; - int ret = 1; - secp256k1_gej Qj; - secp256k1_ge Q; - secp256k1_scalar sec; - - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sec32 != NULL); - ARG_CHECK(pubnonce != NULL); - ARG_CHECK(privnonce32 != NULL); - - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - do { - int overflow; - ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&sec, privnonce32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&sec)) { - continue; - } - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec); - secp256k1_ge_set_gej(&Q, &Qj); - - secp256k1_pubkey_save(pubnonce, &Q); - break; - } while(1); - - secp256k1_scalar_clear(&sec); - if (!ret) { - memset(pubnonce, 0, sizeof(*pubnonce)); - } - return ret; -} - -int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) { - int overflow = 0; - secp256k1_scalar sec, non; - secp256k1_ge pubnon; - VERIFY_CHECK(ctx != NULL); - ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - ARG_CHECK(msg32 != NULL); - ARG_CHECK(sig64 != NULL); - ARG_CHECK(sec32 != NULL); - ARG_CHECK(secnonce32 != NULL); - ARG_CHECK(pubnonce_others != NULL); - - secp256k1_scalar_set_b32(&sec, sec32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&sec)) { - return -1; - } - secp256k1_scalar_set_b32(&non, secnonce32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&non)) { - return -1; - } - secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others); - return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32); -} - -int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) { - ARG_CHECK(sig64 != NULL); - ARG_CHECK(n >= 1); - ARG_CHECK(sig64sin != NULL); - return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); -} - -#endif diff --git a/src/modules/schnorr/schnorr.h b/src/modules/schnorr/schnorr.h deleted file mode 100644 index de18147bd..000000000 --- a/src/modules/schnorr/schnorr.h +++ /dev/null @@ -1,20 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014-2015 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_SCHNORR_H_ -#define _SECP256K1_MODULE_SCHNORR_H_ - -#include "scalar.h" -#include "group.h" - -typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); - -static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32); -static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); -static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); -static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins); - -#endif diff --git a/src/modules/schnorr/schnorr_impl.h b/src/modules/schnorr/schnorr_impl.h deleted file mode 100644 index e13ab6db7..000000000 --- a/src/modules/schnorr/schnorr_impl.h +++ /dev/null @@ -1,207 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2014-2015 Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or http://www.opensource.org/licenses/mit-license.php. * - ***********************************************************************/ - -#ifndef _SECP256K1_SCHNORR_IMPL_H_ -#define _SECP256K1_SCHNORR_IMPL_H_ - -#include - -#include "schnorr.h" -#include "num.h" -#include "field.h" -#include "group.h" -#include "ecmult.h" -#include "ecmult_gen.h" - -/** - * Custom Schnorr-based signature scheme. They support multiparty signing, public key - * recovery and batch validation. - * - * Rationale for verifying R's y coordinate: - * In order to support batch validation and public key recovery, the full R point must - * be known to verifiers, rather than just its x coordinate. In order to not risk - * being more strict in batch validation than normal validation, validators must be - * required to reject signatures with incorrect y coordinate. This is only possible - * by including a (relatively slow) field inverse, or a field square root. However, - * batch validation offers potentially much higher benefits than this cost. - * - * Rationale for having an implicit y coordinate oddness: - * If we commit to having the full R point known to verifiers, there are two mechanism. - * Either include its oddness in the signature, or give it an implicit fixed value. - * As the R y coordinate can be flipped by a simple negation of the nonce, we choose the - * latter, as it comes with nearly zero impact on signing or validation performance, and - * saves a byte in the signature. - * - * Signing: - * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0) - * - * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce). - * Compute 32-byte r, the serialization of R's x coordinate. - * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order. - * Compute scalar s = k - h * x. - * The signature is (r, s). - * - * - * Verification: - * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s) - * - * Signature is invalid if s >= order. - * Signature is invalid if r >= p. - * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order. - * Option 1 (faster for single verification): - * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd. - * Signature is valid if the serialization of R's x coordinate equals r. - * Option 2 (allows batch validation and pubkey recovery): - * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve. - * Signature is valid if R + h * Q + s * G == 0. - */ - -static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { - secp256k1_gej Rj; - secp256k1_ge Ra; - unsigned char h32[32]; - secp256k1_scalar h, s; - int overflow; - secp256k1_scalar n; - - if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { - return 0; - } - n = *nonce; - - secp256k1_ecmult_gen(ctx, &Rj, &n); - if (pubnonce != NULL) { - secp256k1_gej_add_ge(&Rj, &Rj, pubnonce); - } - secp256k1_ge_set_gej(&Ra, &Rj); - secp256k1_fe_normalize(&Ra.y); - if (secp256k1_fe_is_odd(&Ra.y)) { - /* R's y coordinate is odd, which is not allowed (see rationale above). - Force it to be even by negating the nonce. Note that this even works - for multiparty signing, as the R point is known to all participants, - which can all decide to flip the sign in unison, resulting in the - overall R point to be negated too. */ - secp256k1_scalar_negate(&n, &n); - } - secp256k1_fe_normalize(&Ra.x); - secp256k1_fe_get_b32(sig64, &Ra.x); - hash(h32, sig64, msg32); - overflow = 0; - secp256k1_scalar_set_b32(&h, h32, &overflow); - if (overflow || secp256k1_scalar_is_zero(&h)) { - secp256k1_scalar_clear(&n); - return 0; - } - secp256k1_scalar_mul(&s, &h, key); - secp256k1_scalar_negate(&s, &s); - secp256k1_scalar_add(&s, &s, &n); - secp256k1_scalar_clear(&n); - secp256k1_scalar_get_b32(sig64 + 32, &s); - return 1; -} - -static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { - secp256k1_gej Qj, Rj; - secp256k1_ge Ra; - secp256k1_fe Rx; - secp256k1_scalar h, s; - unsigned char hh[32]; - int overflow; - - if (secp256k1_ge_is_infinity(pubkey)) { - return 0; - } - hash(hh, sig64, msg32); - overflow = 0; - secp256k1_scalar_set_b32(&h, hh, &overflow); - if (overflow || secp256k1_scalar_is_zero(&h)) { - return 0; - } - overflow = 0; - secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); - if (overflow) { - return 0; - } - if (!secp256k1_fe_set_b32(&Rx, sig64)) { - return 0; - } - secp256k1_gej_set_ge(&Qj, pubkey); - secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); - if (secp256k1_gej_is_infinity(&Rj)) { - return 0; - } - secp256k1_ge_set_gej_var(&Ra, &Rj); - secp256k1_fe_normalize_var(&Ra.y); - if (secp256k1_fe_is_odd(&Ra.y)) { - return 0; - } - return secp256k1_fe_equal_var(&Rx, &Ra.x); -} - -static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { - secp256k1_gej Qj, Rj; - secp256k1_ge Ra; - secp256k1_fe Rx; - secp256k1_scalar h, s; - unsigned char hh[32]; - int overflow; - - hash(hh, sig64, msg32); - overflow = 0; - secp256k1_scalar_set_b32(&h, hh, &overflow); - if (overflow || secp256k1_scalar_is_zero(&h)) { - return 0; - } - overflow = 0; - secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); - if (overflow) { - return 0; - } - if (!secp256k1_fe_set_b32(&Rx, sig64)) { - return 0; - } - if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) { - return 0; - } - secp256k1_gej_set_ge(&Rj, &Ra); - secp256k1_scalar_inverse_var(&h, &h); - secp256k1_scalar_negate(&s, &s); - secp256k1_scalar_mul(&s, &s, &h); - secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s); - if (secp256k1_gej_is_infinity(&Qj)) { - return 0; - } - secp256k1_ge_set_gej(pubkey, &Qj); - return 1; -} - -static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) { - secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - size_t i; - for (i = 0; i < n; i++) { - secp256k1_scalar si; - int overflow; - secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow); - if (overflow) { - return -1; - } - if (i) { - if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) { - return -1; - } - } - secp256k1_scalar_add(&s, &s, &si); - } - if (secp256k1_scalar_is_zero(&s)) { - return 0; - } - memcpy(sig64, sig64ins[0], 32); - secp256k1_scalar_get_b32(sig64 + 32, &s); - secp256k1_scalar_clear(&s); - return 1; -} - -#endif diff --git a/src/modules/schnorr/tests_impl.h b/src/modules/schnorr/tests_impl.h deleted file mode 100644 index 5bd14a03e..000000000 --- a/src/modules/schnorr/tests_impl.h +++ /dev/null @@ -1,175 +0,0 @@ -/********************************************************************** - * Copyright (c) 2014-2015 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_SCHNORR_TESTS -#define SECP256K1_MODULE_SCHNORR_TESTS - -#include "include/secp256k1_schnorr.h" - -void test_schnorr_end_to_end(void) { - unsigned char privkey[32]; - unsigned char message[32]; - unsigned char schnorr_signature[64]; - secp256k1_pubkey pubkey, recpubkey; - - /* Generate a random key and message. */ - { - secp256k1_scalar key; - random_scalar_order_test(&key); - secp256k1_scalar_get_b32(privkey, &key); - secp256k1_rand256_test(message); - } - - /* Construct and verify corresponding public key. */ - CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); - - /* Schnorr sign. */ - CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); - CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); - CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1); - CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); - /* Destroy signature and verify again. */ - schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); - CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0); - CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 || - memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); -} - -/** Horribly broken hash function. Do not use for anything but tests. */ -void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { - int i; - for (i = 0; i < 32; i++) { - h32[i] = r32[i] ^ msg32[i]; - } -} - -void test_schnorr_sign_verify(void) { - unsigned char msg32[32]; - unsigned char sig64[3][64]; - secp256k1_gej pubkeyj[3]; - secp256k1_ge pubkey[3]; - secp256k1_scalar nonce[3], key[3]; - int i = 0; - int k; - - secp256k1_rand256_test(msg32); - - for (k = 0; k < 3; k++) { - random_scalar_order_test(&key[k]); - - do { - random_scalar_order_test(&nonce[k]); - if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) { - break; - } - } while(1); - - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]); - secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]); - CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32)); - - for (i = 0; i < 4; i++) { - int pos = secp256k1_rand_bits(6); - int mod = 1 + secp256k1_rand_int(255); - sig64[k][pos] ^= mod; - CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0); - sig64[k][pos] ^= mod; - } - } -} - -void test_schnorr_threshold(void) { - unsigned char msg[32]; - unsigned char sec[5][32]; - secp256k1_pubkey pub[5]; - unsigned char nonce[5][32]; - secp256k1_pubkey pubnonce[5]; - unsigned char sig[5][64]; - const unsigned char* sigs[5]; - unsigned char allsig[64]; - const secp256k1_pubkey* pubs[5]; - secp256k1_pubkey allpub; - int n, i; - int damage; - int ret = 0; - - damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; - secp256k1_rand256_test(msg); - n = 2 + secp256k1_rand_int(4); - for (i = 0; i < n; i++) { - do { - secp256k1_rand256_test(sec[i]); - } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); - CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); - CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); - pubs[i] = &pub[i]; - } - if (damage == 1) { - nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } else if (damage == 2) { - sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - for (i = 0; i < n; i++) { - secp256k1_pubkey allpubnonce; - const secp256k1_pubkey *pubnonces[4]; - int j; - for (j = 0; j < i; j++) { - pubnonces[j] = &pubnonce[j]; - } - for (j = i + 1; j < n; j++) { - pubnonces[j - 1] = &pubnonce[j]; - } - CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); - ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; - sigs[i] = sig[i]; - } - if (damage == 3) { - sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); - } - ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; - if ((ret & 1) == 0) { - ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; - } - if (damage == 4) { - allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); - } - if ((ret & 7) == 0) { - ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; - } - CHECK((ret == 0) == (damage == 0)); -} - -void test_schnorr_recovery(void) { - unsigned char msg32[32]; - unsigned char sig64[64]; - secp256k1_ge Q; - - secp256k1_rand256_test(msg32); - secp256k1_rand256_test(sig64); - secp256k1_rand256_test(sig64 + 32); - if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) { - CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1); - } -} - -void run_schnorr_tests(void) { - int i; - for (i = 0; i < 32*count; i++) { - test_schnorr_end_to_end(); - } - for (i = 0; i < 32 * count; i++) { - test_schnorr_sign_verify(); - } - for (i = 0; i < 16 * count; i++) { - test_schnorr_recovery(); - } - for (i = 0; i < 10 * count; i++) { - test_schnorr_threshold(); - } -} - -#endif diff --git a/src/num.h b/src/num.h index ebfa71eb4..7bb9c5be8 100644 --- a/src/num.h +++ b/src/num.h @@ -32,6 +32,9 @@ static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsi /** Compute a modular inverse. The input must be less than the modulus. */ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m); +/** Compute the jacobi symbol (a|b). b must be positive and odd. */ +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b); + /** Compare the absolute value of two numbers. */ static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b); @@ -57,6 +60,9 @@ static void secp256k1_num_shift(secp256k1_num *r, int bits); /** Check whether a number is zero. */ static int secp256k1_num_is_zero(const secp256k1_num *a); +/** Check whether a number is one. */ +static int secp256k1_num_is_one(const secp256k1_num *a); + /** Check whether a number is strictly negative. */ static int secp256k1_num_is_neg(const secp256k1_num *a); diff --git a/src/num_gmp_impl.h b/src/num_gmp_impl.h index 7b6a89719..3a46495ee 100644 --- a/src/num_gmp_impl.h +++ b/src/num_gmp_impl.h @@ -144,6 +144,32 @@ static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, memset(v, 0, sizeof(v)); } +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) { + int ret; + mpz_t ga, gb; + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1)); + + mpz_inits(ga, gb, NULL); + + mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data); + mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data); + if (a->neg) { + mpz_neg(ga, ga); + } + + ret = mpz_jacobi(ga, gb); + + mpz_clears(ga, gb, NULL); + + return ret; +} + +static int secp256k1_num_is_one(const secp256k1_num *a) { + return (a->limbs == 1 && a->data[0] == 1); +} + static int secp256k1_num_is_zero(const secp256k1_num *a) { return (a->limbs == 1 && a->data[0] == 0); } diff --git a/src/scalar.h b/src/scalar.h index b590ccd6d..27e9d8375 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -13,7 +13,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32.h" diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index aa2703dd2..56e7bd82a 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -282,8 +282,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq 56(%%rsi), %%r14\n" /* Initialize r8,r9,r10 */ "movq 0(%%rsi), %%r8\n" - "movq $0, %%r9\n" - "movq $0, %%r10\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" /* (r8,r9) += n0 * c0 */ "movq %8, %%rax\n" "mulq %%r11\n" @@ -291,7 +291,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq %%rdx, %%r9\n" /* extract m0 */ "movq %%r8, %q0\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10) += l1 */ "addq 8(%%rsi), %%r9\n" "adcq $0, %%r10\n" @@ -309,7 +309,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r8\n" /* extract m1 */ "movq %%r9, %q1\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r10,r8,r9) += l2 */ "addq 16(%%rsi), %%r10\n" "adcq $0, %%r8\n" @@ -332,7 +332,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r9\n" /* extract m2 */ "movq %%r10, %q2\n" - "movq $0, %%r10\n" + "xorq %%r10, %%r10\n" /* (r8,r9,r10) += l3 */ "addq 24(%%rsi), %%r8\n" "adcq $0, %%r9\n" @@ -355,7 +355,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r10\n" /* extract m3 */ "movq %%r8, %q3\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10,r8) += n3 * c1 */ "movq %9, %%rax\n" "mulq %%r14\n" @@ -387,8 +387,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq %q11, %%r13\n" /* Initialize (r8,r9,r10) */ "movq %q5, %%r8\n" - "movq $0, %%r9\n" - "movq $0, %%r10\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" /* (r8,r9) += m4 * c0 */ "movq %12, %%rax\n" "mulq %%r11\n" @@ -396,7 +396,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq %%rdx, %%r9\n" /* extract p0 */ "movq %%r8, %q0\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10) += m1 */ "addq %q6, %%r9\n" "adcq $0, %%r10\n" @@ -414,7 +414,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r8\n" /* extract p1 */ "movq %%r9, %q1\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r10,r8,r9) += m2 */ "addq %q7, %%r10\n" "adcq $0, %%r8\n" @@ -472,7 +472,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "movq %%rax, 0(%q6)\n" /* Move to (r8,r9) */ "movq %%rdx, %%r8\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r8,r9) += p1 */ "addq %q2, %%r8\n" "adcq $0, %%r9\n" @@ -483,7 +483,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq %%rdx, %%r9\n" /* Extract r1 */ "movq %%r8, 8(%q6)\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r8) += p4 */ "addq %%r10, %%r9\n" "adcq $0, %%r8\n" @@ -492,7 +492,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) "adcq $0, %%r8\n" /* Extract r2 */ "movq %%r9, 16(%q6)\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r8,r9) += p3 */ "addq %q4, %%r8\n" "adcq $0, %%r9\n" diff --git a/src/scalar_impl.h b/src/scalar_impl.h index 88ea97de8..f5b237640 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -7,8 +7,6 @@ #ifndef _SECP256K1_SCALAR_IMPL_H_ #define _SECP256K1_SCALAR_IMPL_H_ -#include - #include "group.h" #include "scalar.h" @@ -16,7 +14,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low_impl.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64_impl.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32_impl.h" @@ -33,17 +33,37 @@ static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a /** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ static void secp256k1_scalar_order_get_num(secp256k1_num *r) { +#if defined(EXHAUSTIVE_TEST_ORDER) + static const unsigned char order[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,EXHAUSTIVE_TEST_ORDER + }; +#else static const unsigned char order[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 }; +#endif secp256k1_num_set_bin(r, order, 32); } #endif static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { +#if defined(EXHAUSTIVE_TEST_ORDER) + int i; + *r = 0; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) + *r = i; + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(*r != 0); +} +#else secp256k1_scalar *t; int i; /* First compute x ^ (2^N - 1) for some values of N. */ @@ -235,9 +255,9 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar } SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { - /* d[0] is present and is the lowest word for all representations */ return !(a->d[0] & 1); } +#endif static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { #if defined(USE_SCALAR_INV_BUILTIN) @@ -261,6 +281,18 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc } #ifdef USE_ENDOMORPHISM +#if defined(EXHAUSTIVE_TEST_ORDER) +/** + * 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 + * nontrivial to get full test coverage for the exhaustive tests. We therefore + * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. + */ +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; +} +#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, @@ -333,5 +365,6 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar secp256k1_scalar_add(r1, r1, a); } #endif +#endif #endif diff --git a/src/scalar_low.h b/src/scalar_low.h new file mode 100644 index 000000000..5574c44c7 --- /dev/null +++ b/src/scalar_low.h @@ -0,0 +1,15 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef uint32_t secp256k1_scalar; + +#endif diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h new file mode 100644 index 000000000..4f94441f4 --- /dev/null +++ b/src/scalar_low_impl.h @@ -0,0 +1,114 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +#include "scalar.h" + +#include + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + return !(*a & 1); +} + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; } +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; } + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + if (offset < 32) + return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); + else + return 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + return secp256k1_scalar_get_bits(a, offset, count); +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + return *r < *b; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + if (flag && bit < 32) + *r += (1 << bit); +#ifdef VERIFY + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; + int i; + *r = 0; + for (i = 0; i < 32; i++) { + *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; + } + /* just deny overflow, it basically always happens */ + if (overflow) *overflow = 0; +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + memset(bin, 0, 32); + bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + return *a == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + if (*a == 0) { + *r = 0; + } else { + *r = EXHAUSTIVE_TEST_ORDER - *a; + } +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + return *a == 1; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + return *a > EXHAUSTIVE_TEST_ORDER / 2; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + if (flag) secp256k1_scalar_negate(r, r); + return flag ? -1 : 1; +} + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; +} + +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = *r & ((1 << n) - 1); + *r >>= n; + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; +} + +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + *r1 = *a; + *r2 = 0; +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + return *a == *b; +} + +#endif diff --git a/src/secp256k1.c b/src/secp256k1.c old mode 100644 new mode 100755 index 62d192bae..fb8b882fa --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -4,8 +4,6 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#define SECP256K1_BUILD (1) - #include "include/secp256k1.h" #include "util.h" @@ -152,7 +150,6 @@ static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { secp256k1_ge Q; - (void)ctx; VERIFY_CHECK(ctx != NULL); ARG_CHECK(pubkey != NULL); memset(pubkey, 0, sizeof(*pubkey)); @@ -170,7 +167,6 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o size_t len; int ret = 0; - (void)ctx; VERIFY_CHECK(ctx != NULL); ARG_CHECK(outputlen != NULL); ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); @@ -216,7 +212,7 @@ static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { secp256k1_scalar r, s; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(input != NULL); @@ -234,7 +230,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25 int ret = 1; int overflow = 0; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(sig != NULL); ARG_CHECK(input64 != NULL); @@ -253,7 +249,7 @@ int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp25 int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { secp256k1_scalar r, s; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(output != NULL); ARG_CHECK(outputlen != NULL); ARG_CHECK(sig != NULL); @@ -265,7 +261,7 @@ int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsign int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { secp256k1_scalar r, s; - (void)ctx; + VERIFY_CHECK(ctx != NULL); ARG_CHECK(output64 != NULL); ARG_CHECK(sig != NULL); @@ -363,16 +359,15 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; unsigned int count = 0; secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { - unsigned char nonce32[32]; ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); if (!overflow && !secp256k1_scalar_is_zero(&non)) { if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { break; @@ -380,6 +375,7 @@ int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature } count++; } + memset(nonce32, 0, 32); secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); @@ -398,7 +394,6 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char int overflow; VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); - (void)ctx; secp256k1_scalar_set_b32(&sec, seckey, &overflow); ret = !overflow && !secp256k1_scalar_is_zero(&sec); @@ -437,7 +432,6 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char * VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); ARG_CHECK(tweak != NULL); - (void)ctx; secp256k1_scalar_set_b32(&term, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); @@ -485,7 +479,6 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char * VERIFY_CHECK(ctx != NULL); ARG_CHECK(seckey != NULL); ARG_CHECK(tweak != NULL); - (void)ctx; secp256k1_scalar_set_b32(&factor, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); diff --git a/src/tests.c b/src/tests.c index 687a5f2fd..9ae7d3028 100644 --- a/src/tests.c +++ b/src/tests.c @@ -473,6 +473,8 @@ void test_num_negate(void) { } void test_num_add_sub(void) { + int i; + secp256k1_scalar s; secp256k1_num n1; secp256k1_num n2; secp256k1_num n1p2, n2p1, n1m2, n2m1; @@ -498,6 +500,110 @@ void test_num_add_sub(void) { CHECK(!secp256k1_num_eq(&n2p1, &n1)); secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ CHECK(secp256k1_num_eq(&n2p1, &n1)); + + /* check is_one */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&n1, &s); + CHECK(secp256k1_num_is_one(&n1)); + /* check that 2^n + 1 is never 1 */ + secp256k1_scalar_get_num(&n2, &s); + for (i = 0; i < 250; ++i) { + secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */ + secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */ + CHECK(!secp256k1_num_is_one(&n1p2)); + } +} + +void test_num_mod(void) { + int i; + secp256k1_scalar s; + secp256k1_num order, n; + + /* check that 0 mod anything is 0 */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_set_int(&s, 0); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that anything mod 1 is 0 */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that increasing the number past 2^256 does not break this */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&n, &s); + /* multiply by 2^8, which'll test this case with high probability */ + for (i = 0; i < 8; ++i) { + secp256k1_num_add(&n, &n, &n); + } + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); +} + +void test_num_jacobi(void) { + secp256k1_scalar sqr; + secp256k1_scalar small; + secp256k1_scalar five; /* five is not a quadratic residue */ + secp256k1_num order, n; + int i; + /* squares mod 5 are 1, 4 */ + const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 }; + + /* check some small values with 5 as the order */ + secp256k1_scalar_set_int(&five, 5); + secp256k1_scalar_get_num(&order, &five); + for (i = 0; i < 10; ++i) { + secp256k1_scalar_set_int(&small, i); + secp256k1_scalar_get_num(&n, &small); + CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]); + } + + /** test large values with 5 as group order */ + secp256k1_scalar_get_num(&order, &five); + /* we first need a scalar which is not a multiple of 5 */ + do { + secp256k1_num fiven; + random_scalar_order_test(&sqr); + secp256k1_scalar_get_num(&fiven, &five); + secp256k1_scalar_get_num(&n, &sqr); + secp256k1_num_mod(&n, &fiven); + } while (secp256k1_num_is_zero(&n)); + /* next force it to be a residue. 2 is a nonresidue mod 5 so we can + * just multiply by two, i.e. add the number to itself */ + if (secp256k1_num_jacobi(&n, &order) == -1) { + secp256k1_num_add(&n, &n, &n); + } + + /* test residue */ + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_num_add(&n, &n, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + + /** test with secp group order as order */ + secp256k1_scalar_order_get_num(&order); + random_scalar_order_test(&sqr); + secp256k1_scalar_sqr(&sqr, &sqr); + /* test residue */ + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_scalar_mul(&sqr, &sqr, &five); + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + /* test multiple of the order*/ + CHECK(secp256k1_num_jacobi(&order, &order) == 0); + + /* check one less than the order */ + secp256k1_scalar_set_int(&small, 1); + secp256k1_scalar_get_num(&n, &small); + secp256k1_num_sub(&n, &order, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */ } void run_num_smalltests(void) { @@ -505,6 +611,8 @@ void run_num_smalltests(void) { for (i = 0; i < 100*count; i++) { test_num_negate(); test_num_add_sub(); + test_num_mod(); + test_num_jacobi(); } } #endif @@ -689,6 +797,10 @@ void scalar_test(void) { secp256k1_scalar_inverse(&inv, &inv); /* Inverting one must result in one. */ CHECK(secp256k1_scalar_is_one(&inv)); +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&invnum, &inv); + CHECK(secp256k1_num_is_one(&invnum)); +#endif } } @@ -855,7 +967,7 @@ void run_scalar_tests(void) { secp256k1_scalar zzv; #endif int overflow; - unsigned char chal[32][2][32] = { + unsigned char chal[33][2][32] = { {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, @@ -1111,9 +1223,17 @@ void run_scalar_tests(void) { {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}} + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, + {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, + {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} }; - unsigned char res[32][2][32] = { + unsigned char res[33][2][32] = { {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, @@ -1369,10 +1489,18 @@ void run_scalar_tests(void) { {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, - 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}} + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, + {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, + {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} }; secp256k1_scalar_set_int(&one, 1); - for (i = 0; i < 32; i++) { + for (i = 0; i < 33; i++) { secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); CHECK(!overflow); secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); @@ -1446,7 +1574,7 @@ void random_fe_non_zero(secp256k1_fe *nz) { void random_fe_non_square(secp256k1_fe *ns) { secp256k1_fe r; random_fe_non_zero(ns); - if (secp256k1_fe_sqrt_var(&r, ns)) { + if (secp256k1_fe_sqrt(&r, ns)) { secp256k1_fe_negate(ns, ns, 1); } } @@ -1605,18 +1733,18 @@ void run_field_inv_all_var(void) { secp256k1_fe x[16], xi[16], xii[16]; int i; /* Check it's safe to call for 0 elements */ - secp256k1_fe_inv_all_var(0, xi, x); + 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; for (j = 0; j < len; j++) { random_fe_non_zero(&x[j]); } - secp256k1_fe_inv_all_var(len, xi, x); + secp256k1_fe_inv_all_var(xi, x, len); for (j = 0; j < len; j++) { CHECK(check_fe_inverse(&x[j], &xi[j])); } - secp256k1_fe_inv_all_var(len, xii, xi); + secp256k1_fe_inv_all_var(xii, xi, len); for (j = 0; j < len; j++) { CHECK(check_fe_equal(&x[j], &xii[j])); } @@ -1641,7 +1769,7 @@ void run_sqr(void) { void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { secp256k1_fe r1, r2; - int v = secp256k1_fe_sqrt_var(&r1, a); + int v = secp256k1_fe_sqrt(&r1, a); CHECK((v == 0) == (k == NULL)); if (k != NULL) { @@ -1802,7 +1930,7 @@ void test_ge(void) { zs[i] = gej[i].z; } } - secp256k1_fe_inv_all_var(4 * runs + 1, zinv, zs); + secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1); free(zs); } @@ -1922,8 +2050,8 @@ void test_ge(void) { secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); } } - secp256k1_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr); - secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback); + secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1); + secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback); for (i = 0; i < 4 * runs + 1; i++) { secp256k1_fe s; random_fe_non_zero(&s); @@ -1951,8 +2079,8 @@ void test_add_neg_y_diff_x(void) { * of the sum to be wrong (since infinity has no xy coordinates). * HOWEVER, if the x-coordinates are different, infinity is the * wrong answer, and such degeneracies are exposed. This is the - * root of https://github.com/bitcoin/secp256k1/issues/257 which - * this test is a regression test for. + * root of https://github.com/bitcoin-core/secp256k1/issues/257 + * which this test is a regression test for. * * These points were generated in sage as * # secp256k1 params @@ -2051,15 +2179,16 @@ void run_ec_combine(void) { void test_group_decompress(const secp256k1_fe* x) { /* The input itself, normalized. */ secp256k1_fe fex = *x; - secp256k1_fe tmp; + secp256k1_fe fez; /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ secp256k1_ge ge_quad, ge_even, ge_odd; + secp256k1_gej gej_quad; /* Return values of the above calls. */ int res_quad, res_even, res_odd; secp256k1_fe_normalize_var(&fex); - res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex); + res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex); res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); @@ -2085,13 +2214,29 @@ void test_group_decompress(const secp256k1_fe* x) { CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); /* Check that the Y coordinate result in ge_quad is a square. */ - CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y)); - secp256k1_fe_sqr(&tmp, &tmp); - CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y)); + CHECK(secp256k1_fe_is_quad_var(&ge_quad.y)); /* Check odd/even Y in ge_odd, ge_even. */ CHECK(secp256k1_fe_is_odd(&ge_odd.y)); CHECK(!secp256k1_fe_is_odd(&ge_even.y)); + + /* Check secp256k1_gej_has_quad_y_var. */ + secp256k1_gej_set_ge(&gej_quad, &ge_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); } } @@ -2383,9 +2528,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, shift; int wnaf[256] = {0}; int i; -#ifdef USE_ENDOMORPHISM int skew; -#endif secp256k1_scalar num = *number; secp256k1_scalar_set_int(&x, 0); @@ -2395,10 +2538,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { for (i = 0; i < 16; ++i) { secp256k1_scalar_shr_int(&num, 8); } - skew = secp256k1_wnaf_const(wnaf, num, w); -#else - secp256k1_wnaf_const(wnaf, num, w); #endif + skew = secp256k1_wnaf_const(wnaf, num, w); for (i = WNAF_SIZE(w); i >= 0; --i) { secp256k1_scalar t; @@ -2417,10 +2558,8 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) { } secp256k1_scalar_add(&x, &x, &t); } -#ifdef USE_ENDOMORPHISM - /* Skew num because when encoding 128-bit numbers as odd we use an offset */ + /* Skew num because when encoding numbers as odd we use an offset */ secp256k1_scalar_cadd_bit(&num, skew == 2, 1); -#endif CHECK(secp256k1_scalar_eq(&x, &num)); } @@ -3484,12 +3623,14 @@ void run_ecdsa_end_to_end(void) { int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { static const unsigned char zeroes[32] = {0}; +#ifdef ENABLE_OPENSSL_TESTS static const unsigned char max_scalar[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 }; +#endif int ret = 0; @@ -3607,13 +3748,13 @@ 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); - if (action < 1) { + if (action < 1 && *len > 3) { /* Delete a byte. */ pos = secp256k1_rand_int(*len); memmove(sig + pos, sig + pos + 1, *len - pos - 1); (*len)--; return; - } else if (action < 2) { + } else if (action < 2 && *len < 2048) { /* Insert a byte. */ pos = secp256k1_rand_int(1 + *len); memmove(sig + pos + 1, sig + pos, *len - pos); @@ -3785,6 +3926,7 @@ void run_ecdsa_der_parse(void) { int certainly_der = 0; int certainly_not_der = 0; random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + CHECK(buflen <= 2048); for (j = 0; j < 16; j++) { int ret = 0; if (j > 0) { diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c new file mode 100644 index 000000000..bda6ee475 --- /dev/null +++ b/src/tests_exhaustive.c @@ -0,0 +1,329 @@ +/*********************************************************************** + * 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.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include + +#include + +#undef USE_ECMULT_STATIC_PRECOMPUTATION + +#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" +#include "group.h" +#include "secp256k1.c" +#include "testrand_impl.h" + +/** stolen from tests.c */ +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); +} + +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); +} + +void random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} +/** END stolen from tests.c */ + +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) { + secp256k1_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)algo16; + /* Some nonces cannot be used because they'd cause s and/or r to be zero. + * The signing function has retry logic here that just re-calls the nonce + * function with an increased `attempt`. So if attempt > 0 this means we + * need to change the nonce to avoid an infinite loop. */ + if (attempt > 0) { + (*idata)++; + } + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +#ifdef USE_ENDOMORPHISM +void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) { + int i; + for (i = 0; i < 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) { + int i, j; + + /* 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++) { + CHECK(!secp256k1_ge_is_infinity(&group[i])); + CHECK(!secp256k1_gej_is_infinity(&groupj[i])); + } + + /* Check all addition formulae */ + for (j = 0; j < order; j++) { + secp256k1_fe fe_inv; + secp256k1_fe_inv(&fe_inv, &groupj[j].z); + for (i = 0; i < 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); + /* add_ge */ + if (j > 0) { + secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + /* add_ge_var */ + secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); + ge_equals_gej(&group[(i + j) % 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); + } + } + + /* Check doubling */ + for (i = 0; i < order; i++) { + secp256k1_gej tmp; + if (i > 0) { + secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + secp256k1_gej_double_var(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + + /* Check negation */ + for (i = 1; i < order; i++) { + secp256k1_ge tmp; + secp256k1_gej tmpj; + secp256k1_ge_neg(&tmp, &group[i]); + ge_equals_ge(&group[order - i], &tmp); + secp256k1_gej_neg(&tmpj, &groupj[i]); + ge_equals_gej(&group[order - i], &tmpj); + } +} + +void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { + 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++) { + 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); + + if (i > 0) { + secp256k1_ecmult_const(&tmp, &group[i], &ng); + ge_equals_gej(&group[(i * j) % order], &tmp); + } + } + } + } +} + +void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { + 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); +} + +void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + 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_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 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); + + /* 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 by calling verify */ + secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + secp256k1_scalar_get_b32(msg32, &msg_s); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +void test_exhaustive_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 */ + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + 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(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + 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); + } + } + } + + /* We would like to verify zero-knowledge here by counting how often every + * possible (s, r) tuple appears, but because the group order is larger + * than the field order, when coercing the x-values to scalar values, some + * appear more often than others, so we are actually not zero-knowledge. + * (This effect also appears in the real code, but the difference is on the + * order of 1/2^128th the field order, so the deviation is not useful to a + * computationally bounded attacker.) + */ +} + +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); + + /* TODO set z = 1, then do num_tests runs with random z values */ + + /* 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)); + } + } + + /* 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_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); + + return 0; +} + From 0cc07f82f0d4043e93d8cea49356cd2bc5ffcb27 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Wed, 7 Dec 2016 15:20:40 +0100 Subject: [PATCH 76/91] [QA] add fundrawtransaction test on a locked wallet with empty keypool Github-Pull: #9295 Rebased-From: 1a6eacbf3b7e3d5941fec1154079bbc4678ce861 --- qa/rpc-tests/fundrawtransaction.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py index 8c45578fc..0dcca4cb5 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/qa/rpc-tests/fundrawtransaction.py @@ -484,6 +484,23 @@ def run_test(self): self.is_network_split=False self.sync_all() + # drain the keypool + self.nodes[1].getnewaddress() + inputs = [] + outputs = {self.nodes[0].getnewaddress():1.1} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + # fund a transaction that requires a new key for the change output + # creating the key must be impossible because the wallet is locked + try: + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + raise AssertionError("Wallet unlocked without passphrase") + except JSONRPCException as e: + assert('Keypool ran out' in e.error['message']) + + #refill the keypool + self.nodes[1].walletpassphrase("test", 100) + self.nodes[1].walletlock() + try: self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2) raise AssertionError("Wallet unlocked without passphrase") From 43bcfca48970b65d4eb215f20047bb99495f3727 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Tue, 6 Dec 2016 13:45:56 +0100 Subject: [PATCH 77/91] [Wallet] Bugfix: FRT: don't terminate when keypool is empty Github-Pull: #9295 Rebased-From: c24a4f5981d47d55aa9e4eb40294832a4d38fb80 --- src/wallet/wallet.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6ce8d19bf..5b35e49a0 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2290,7 +2290,11 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt CPubKey vchPubKey; bool ret; ret = reservekey.GetReservedKey(vchPubKey); - assert(ret); // should never fail, as we just unlocked + if (!ret) + { + strFailReason = _("Keypool ran out, please call keypoolrefill first"); + return false; + } scriptChange = GetScriptForDestination(vchPubKey.GetID()); } From a0f7ececfd096df398fc5e4aad07f1a43760afb4 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Mon, 12 Dec 2016 08:10:27 +0000 Subject: [PATCH 78/91] Update for OpenSSL 1.1 API Github-Pull: #9326 Rebased-From: bae1eef752dcecfd85fa482881e1dbe4d7e9f74c b05b1af10b9a5298bd90bea439f0fd6c636e0cfa --- src/qt/paymentrequestplus.cpp | 20 +++++++++++++++----- src/wallet/test/crypto_tests.cpp | 32 ++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 20e1f79ff..82be4d831 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -159,14 +159,24 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c std::string data_to_verify; // Everything but the signature rcopy.SerializeToString(&data_to_verify); - EVP_MD_CTX ctx; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context."); +#else + EVP_MD_CTX _ctx; + EVP_MD_CTX *ctx; + ctx = &_ctx; +#endif EVP_PKEY *pubkey = X509_get_pubkey(signing_cert); - EVP_MD_CTX_init(&ctx); - if (!EVP_VerifyInit_ex(&ctx, digestAlgorithm, NULL) || - !EVP_VerifyUpdate(&ctx, data_to_verify.data(), data_to_verify.size()) || - !EVP_VerifyFinal(&ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) { + EVP_MD_CTX_init(ctx); + if (!EVP_VerifyInit_ex(ctx, digestAlgorithm, NULL) || + !EVP_VerifyUpdate(ctx, data_to_verify.data(), data_to_verify.size()) || + !EVP_VerifyFinal(ctx, (const unsigned char*)paymentRequest.signature().data(), (unsigned int)paymentRequest.signature().size(), pubkey)) { throw SSLVerifyError("Bad signature, invalid payment request."); } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_MD_CTX_free(ctx); +#endif // OpenSSL API for getting human printable strings from certs is baroque. int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, NULL, 0); diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp index 05387f5f2..b235b9609 100644 --- a/src/wallet/test/crypto_tests.cpp +++ b/src/wallet/test/crypto_tests.cpp @@ -42,15 +42,19 @@ bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0; vchCiphertext = std::vector (nCLen); - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + if (!ctx) return false; bool fOk = true; - EVP_CIPHER_CTX_init(&ctx); - if (fOk) fOk = EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; - if (fOk) fOk = EVP_EncryptUpdate(&ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0; - if (fOk) fOk = EVP_EncryptFinal_ex(&ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0; - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_init(ctx); + if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; + if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0; + if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0; + EVP_CIPHER_CTX_cleanup(ctx); + + EVP_CIPHER_CTX_free(ctx); if (!fOk) return false; @@ -66,15 +70,19 @@ bool OldDecrypt(const std::vector& vchCiphertext, CKeyingMaterial vchPlaintext = CKeyingMaterial(nPLen); - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + if (!ctx) return false; bool fOk = true; - EVP_CIPHER_CTX_init(&ctx); - if (fOk) fOk = EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; - if (fOk) fOk = EVP_DecryptUpdate(&ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0; - if (fOk) fOk = EVP_DecryptFinal_ex(&ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0; - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_init(ctx); + if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, chKey, chIV) != 0; + if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0; + if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0; + EVP_CIPHER_CTX_cleanup(ctx); + + EVP_CIPHER_CTX_free(ctx); if (!fOk) return false; From 35174a0280845e9583a3af1fcf57ee1f98238539 Mon Sep 17 00:00:00 2001 From: Gregory Maxwell Date: Tue, 6 Dec 2016 06:39:14 +0000 Subject: [PATCH 79/91] Make RelayWalletTransaction attempt to AcceptToMemoryPool. This resolves an issue where a wallet transaction which failed to relay previously because it couldn't make it into the mempool will not try again until restart, even though mempool conditions may have changed. Abandoned and known-conflicted transactions are skipped. Some concern was expressed that there may be users with many unknown conflicts would waste a lot of CPU time trying to add them to their memory pools over and over again. But I am doubtful these users exist in any number, if they do exist they have worse problems, and they can mitigate any performance issue this might have by abandoning the transactions in question. Github-Pull: #9290 Rebased-From: f692fce8a49e05e25f1c767aae1e50db419caebe --- src/wallet/wallet.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5b35e49a0..0403b3558 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1449,9 +1449,10 @@ void CWallet::ReacceptWalletTransactions() bool CWalletTx::RelayWalletTransaction() { assert(pwallet->GetBroadcastTransactions()); - if (!IsCoinBase()) + if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0) { - if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) { + /* GetDepthInMainChain already catches known conflicts. */ + if (InMempool() || AcceptToMemoryPool(false, maxTxFee)) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); RelayTransaction((CTransaction)*this); return true; From f5d606e5ab0b20881cc0d58d63e6db065c59b411 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 8 Dec 2016 11:49:28 -0800 Subject: [PATCH 80/91] Return txid even if ATMP fails for new transaction Github-Pull: #9302 Rebased-From: b3a74100b86423c553ac327f3ea6fdbc2c50890a --- src/wallet/wallet.cpp | 21 +++++++++++---------- src/wallet/wallet.h | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0403b3558..7f6240262 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1442,7 +1442,8 @@ void CWallet::ReacceptWalletTransactions() CWalletTx& wtx = *(item.second); LOCK(mempool.cs); - wtx.AcceptToMemoryPool(false, maxTxFee); + CValidationState state; + wtx.AcceptToMemoryPool(false, maxTxFee, state); } } @@ -1451,8 +1452,9 @@ bool CWalletTx::RelayWalletTransaction() assert(pwallet->GetBroadcastTransactions()); if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain() == 0) { + CValidationState state; /* GetDepthInMainChain already catches known conflicts. */ - if (InMempool() || AcceptToMemoryPool(false, maxTxFee)) { + if (InMempool() || AcceptToMemoryPool(false, maxTxFee, state)) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); RelayTransaction((CTransaction)*this); return true; @@ -2482,14 +2484,14 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) if (fBroadcastTransactions) { + CValidationState state; // Broadcast - if (!wtxNew.AcceptToMemoryPool(false, maxTxFee)) - { - // This must not fail. The transaction has already been signed and recorded. - LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); - return false; + if (!wtxNew.AcceptToMemoryPool(false, maxTxFee, state)) { + LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason()); + // TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure. + } else { + wtxNew.RelayWalletTransaction(); } - wtxNew.RelayWalletTransaction(); } } return true; @@ -3595,8 +3597,7 @@ int CMerkleTx::GetBlocksToMaturity() const } -bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee) +bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee, CValidationState& state) { - CValidationState state; return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0c95fdf4b..056dcc5da 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -213,7 +213,7 @@ class CMerkleTx : public CTransaction bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; } int GetBlocksToMaturity() const; /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */ - bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee); + bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee, CValidationState& state); bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); } bool isAbandoned() const { return (hashBlock == ABANDON_HASH); } void setAbandoned() { hashBlock = ABANDON_HASH; } From 4ced31325699dc308571010ce004376d2915cd7e Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 14 Dec 2016 17:00:06 -0500 Subject: [PATCH 81/91] Allow compactblock reconstruction when block is in flight --- src/main.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 191bcff4c..976e130f1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5657,6 +5657,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, CBlockHeaderAndShortTxIDs cmpctblock; vRecv >> cmpctblock; + // Keep a CBlock for "optimistic" compactblock reconstructions (see + // below) + CBlock block; + bool fBlockReconstructed = false; + LOCK(cs_main); if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) { @@ -5765,6 +5770,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, req.blockhash = pindex->GetBlockHash(); pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req); } + } else { + // This block is either already in flight from a different + // peer, or this peer has too many blocks outstanding to + // download from. + // Optimistically try to reconstruct anyway since we might be + // able to without any round trips. + PartiallyDownloadedBlock tempBlock(&mempool); + ReadStatus status = tempBlock.InitData(cmpctblock); + if (status != READ_STATUS_OK) { + // TODO: don't ignore failures + return true; + } + std::vector dummy; + status = tempBlock.FillBlock(block, dummy); + if (status == READ_STATUS_OK) { + fBlockReconstructed = true; + } } } else { if (fAlreadyInFlight) { @@ -5785,6 +5807,33 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } } + if (fBlockReconstructed) { + // If we got here, we were able to optimistically reconstruct a + // block that is in flight from some other peer. However, this + // cmpctblock may be invalid. In particular, while we've checked + // that the block merkle root commits to the transaction ids, we + // haven't yet checked that tx witnesses are properly committed to + // in the coinbase witness commitment. + // + // ProcessNewBlock will call MarkBlockAsReceived(), which will + // clear any in-flight compact block state that might be present + // from some other peer. We don't want a malleated compact block + // request to interfere with block relay, so we don't want to call + // ProcessNewBlock until we've already checked that the witness + // commitment is correct. + { + LOCK(cs_main); + CValidationState dummy; + if (!ContextualCheckBlock(block, dummy, pindex->pprev)) { + // TODO: could send reject message to peer? + return true; + } + } + CValidationState state; + ProcessNewBlock(state, chainparams, pfrom, &block, true, NULL, false); + // TODO: could send reject message if block is invalid? + } + CheckBlockIndex(chainparams.GetConsensus()); } From 53b656f3558fe960d9328079ca18eb53418f2652 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Thu, 1 Dec 2016 12:59:10 -0500 Subject: [PATCH 82/91] [qa] Update compactblocks test for multi-peer reconstruction --- qa/rpc-tests/p2p-compactblocks.py | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index e0b72e684..156a559b1 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -757,6 +757,54 @@ def request_cb_announcements(self, peer, node, version): msg.announce = True peer.send_and_ping(msg) + def test_compactblock_reconstruction_multiple_peers(self, node, stalling_peer, delivery_peer): + assert(len(self.utxos)) + + def announce_cmpct_block(node, peer): + utxo = self.utxos.pop(0) + block = self.build_block_with_transactions(node, utxo, 5) + + cmpct_block = HeaderAndShortIDs() + cmpct_block.initialize_from_block(block) + msg = msg_cmpctblock(cmpct_block.to_p2p()) + peer.send_and_ping(msg) + with mininode_lock: + assert(peer.last_getblocktxn is not None) + return block, cmpct_block + + block, cmpct_block = announce_cmpct_block(node, stalling_peer) + + for tx in block.vtx[1:]: + delivery_peer.send_message(msg_tx(tx)) + delivery_peer.sync_with_ping() + mempool = node.getrawmempool() + for tx in block.vtx[1:]: + assert(tx.hash in mempool) + + delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p())) + assert_equal(int(node.getbestblockhash(), 16), block.sha256) + + self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue]) + + # Now test that delivering an invalid compact block won't break relay + + block, cmpct_block = announce_cmpct_block(node, stalling_peer) + for tx in block.vtx[1:]: + delivery_peer.send_message(msg_tx(tx)) + delivery_peer.sync_with_ping() + + cmpct_block.prefilled_txn[0].tx.wit.vtxinwit = [ CTxInWitness() ] + cmpct_block.prefilled_txn[0].tx.wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)] + + cmpct_block.use_witness = True + delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p())) + assert(int(node.getbestblockhash(), 16) != block.sha256) + + msg = msg_blocktxn() + msg.block_transactions.blockhash = block.sha256 + msg.block_transactions.transactions = block.vtx[1:] + stalling_peer.send_and_ping(msg) + assert_equal(int(node.getbestblockhash(), 16), block.sha256) def run_test(self): # Setup the p2p connections and start up the network thread. @@ -841,6 +889,10 @@ def run_test(self): self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False) self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False) + print("\tTesting reconstructing compact blocks from all peers...") + self.test_compactblock_reconstruction_multiple_peers(self.nodes[1], self.segwit_node, self.old_node) + sync_blocks(self.nodes) + # Advance to segwit activation print ("\nAdvancing to segwit activation\n") self.activate_segwit(self.nodes[1]) From c365556185d89122a04344d2dc640cffc67f155c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 5 Dec 2016 23:26:32 -0800 Subject: [PATCH 83/91] Complain when unknown rpcserialversion is specified Github-Pull: #9292 Rebased-From: 80d073c9bca4521d512ea14ff7919d4609647b6d --- src/init.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/init.cpp b/src/init.cpp index 8e40c4388..f2dbf5751 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -364,7 +364,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-port=", strprintf(_("Listen for connections on (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); - strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(>0) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION)); + strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION)); strUsage += HelpMessageOpt("-seednode=", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); strUsage += HelpMessageOpt("-torcontrol=:", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); @@ -986,6 +986,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) return InitError("rpcserialversion must be non-negative."); + if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1) + return InitError("unknown rpcserialversion requested."); + nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); From 49a612f347be150b03eb6ef8fa438d2b06e26993 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 11 Dec 2016 14:12:47 +0100 Subject: [PATCH 84/91] [qa] Don't set unknown rpcserialversion Github-Pull: #9322 Rebased-From: fa615d39b53a9309ef480c41ec073354c4371f40 --- qa/rpc-tests/segwit.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py index 4b4fdf8b1..31a48955e 100755 --- a/qa/rpc-tests/segwit.py +++ b/qa/rpc-tests/segwit.py @@ -85,7 +85,7 @@ def setup_chain(self): def setup_network(self): self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness", "-rpcserialversion=0"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=2"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"])) self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"])) connect_nodes(self.nodes[1], 0) connect_nodes(self.nodes[2], 1) @@ -215,7 +215,6 @@ def run_test(self): assert_equal(len(segwit_tx_list), 5) print("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag") - # Note: node1 has version 2, which is simply >0 and will catch future upgrades in tests assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False)) assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False)) for i in range(len(segwit_tx_list)): From 2c5fc0dba32a6ede1d611554a04a996183aa8ee9 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 19 Dec 2016 13:09:56 +0100 Subject: [PATCH 85/91] doc: Add initial pulls + authors list for 0.13.2 --- doc/release-notes.md | 107 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 0830e0a12..acfb45ae2 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -1,6 +1,6 @@ -Bitcoin Core version 0.13.x is now available from: +Bitcoin Core version 0.13.2 is now available from: - + This is a new minor version release, including ..., various bugfixes and performance improvements, as well as updated translations. @@ -60,7 +60,7 @@ can be abandoned with the previously existing abandontransaction RPC (or in the GUI via a context menu on the transaction). -0.13.x Change log +0.13.2 Change log ================= Detailed release notes follow. This overview includes changes that affect @@ -68,13 +68,110 @@ behavior, not code moves, refactors and string updates. For convenience in locat the code changes and accompanying discussion, both the pull request and git merge commit are mentioned. -(to be filled in at release time) +### Consensus +- #9293 `e591c10` [0.13 Backport #9053] IBD using chainwork instead of height and not using header timestamp (gmaxwell) +- #9053 `5b93eee` IBD using chainwork instead of height and not using header timestamps (gmaxwell) + +### RPC and other APIs +- #8845 `1d048b9` Don't return the address of a P2SH of a P2SH (jnewbery) +- #9041 `87fbced` keypoololdest denote Unix epoch, not GMT (s-matthew-english) +- #9122 `f82c81b` fix getnettotals RPC description about timemillis (visvirial) +- #9042 `5bcb05d` [rpc] ParseHash: Fail when length is not 64 (MarcoFalke) +- #9194 `f26dab7` Add option to return non-segwit serialization via rpc (instagibbs) +- #9347 `b711390` [0.13.2] wallet/rpc backports (MarcoFalke) +- #9292 `c365556` Complain when unknown rpcserialversion is specified (sipa) +- #9322 `49a612f` [qa] Don't set unknown rpcserialversion (MarcoFalke) + +### Block and transaction handling +- #8357 `ce0d817` [mempool] Fix relaypriority calculation error (maiiz) +- #9267 `0a4aa87` [0.13 backport #9239] Disable fee estimates for a confirm target of 1 block (morcos) +- #9196 `0c09d9f` Send tip change notification from invalidateblock (ryanofsky) + +### P2P protocol and network code +- #8995 `9ef3875` Add missing cs_main lock to ::GETBLOCKTXN processing (TheBlueMatt) +- #9234 `94531b5` torcontrol: Explicitly request RSA1024 private key (laanwj) +- #8637 `2cad5db` Compact Block Tweaks (rebase of #8235) (sipa) +- #9058 `286e548` Fixes for p2p-compactblocks.py test timeouts on travis (#8842) (ryanofsky) +- #8865 `4c71fc4` Decouple peer-processing-logic from block-connection-logic (TheBlueMatt) +- #9117 `6fe3981` net: don't send feefilter messages before the version handshake is complete (theuni) +- #9188 `ca1fd75` Make orphan parent fetching ask for witnesses (gmaxwell) +- #9052 `3a3bcbf` Use RelevantServices instead of node_network in AttemptToEvict (gmaxwell) +- #9048 `9460771` [0.13 backport #9026] Fix handling of invalid compact blocks (sdaftuar) +- #9357 `03b6f62` [0.13 backport #9352] Attempt reconstruction from all compact block announcements (sdaftuar) +- #9189 `b96a8f7` Always add default_witness_commitment with GBT client support (sipa) +- #9253 `28d0f22` Fix calculation of number of bound sockets to use (TheBlueMatt) +- #9199 `da5a16b` Always drop the least preferred HB peer when adding a new one (gmaxwell) + +### Build system +- #9169 `d1b4da9` build: fix qt5.7 build under macOS (theuni) +- #9326 `a0f7ece` Update for OpenSSL 1.1 API (gmaxwell) +- #9224 `396c405` Prevent FD_SETSIZE error building on OpenBSD (ivdsangen) + +### GUI +- #8972 `6f86b53` Make warnings label selectable (jonasschnelli) (MarcoFalke) +- #9185 `6d70a73` Fix coincontrol sort issue (jonasschnelli) +- #9094 `5f3a12c` Use correct conversion function for boost::path datadir (laanwj) +- #8908 `4a974b2` Update bitcoin-qt.desktop (s-matthew-english) +- #9190 `dc46b10` Plug many memory leaks (laanwj) + +### Wallet +- #9290 `35174a0` Make RelayWalletTransaction attempt to AcceptToMemoryPool (gmaxwell) +- #9295 `43bcfca` Bugfix: Fundrawtransaction: don't terminate when keypool is empty (jonasschnelli) +- #9302 `f5d606e` Return txid even if ATMP fails for new transaction (sipa) + +### Tests and QA +- #9159 `eca9b46` Wait for specific block announcement in p2p-compactblocks (ryanofsky) +- #9186 `dccdc3a` Fix use-after-free in scheduler tests (laanwj) +- #9168 `3107280` Add assert_raises_message to check specific error message (mrbandrews) +- #9191 `29435db` 0.13.2 Backports (MarcoFalke) +- #9077 `1d4c884` Increase wallet-dump RPC timeout (ryanofsky) +- #9098 `ecd7db5` Handle zombies and cluttered tmpdirs (MarcoFalke) +- #8927 `387ec9d` Add script tests for FindAndDelete in pre-segwit and segwit scripts (jl2012) +- #9200 `eebc699` bench: Fix subtle counting issue when rescaling iteration count (laanwj) + +### Miscellaneous +- #8838 `094848b` Calculate size and weight of block correctly in CreateNewBlock() (jnewbery) +- #8920 `40169dc` Set minimum required Boost to 1.47.0 (fanquake) +- #9251 `a710a43` Improvement of documentation of command line parameter 'whitelist' (wodry) +- #8932 `106da69` Allow bitcoin-tx to create v2 transactions (btcdrak) +- #8929 `12428b4` add software-properties-common (sigwo) +- #9120 `08d1c90` bug: Missed one "return false" in recent refactoring in #9067 (UdjinM6) +- #9067 `f85ee01` Fix exit codes (UdjinM6) +- #9340 `fb987b3` [0.13] Update secp256k1 subtree (MarcoFalke) +- #9229 `b172377` Remove calls to getaddrinfo_a (TheBlueMatt) Credits ======= Thanks to everyone who directly contributed to this release: -(to be filled in at release time) +- Alex Morcos +- BtcDrak +- Cory Fields +- fanquake +- Gregory Maxwell +- Gregory Sanders +- instagibbs +- Ivo van der Sangen +- jnewbery +- Johnson Lau +- Jonas Schnelli +- Luke Dashjr +- maiiz +- MarcoFalke +- Masahiko Hyuga +- Matt Corallo +- matthias +- mrbandrews +- Pavel Janík +- Pieter Wuille +- randy-waterhouse +- Russell Yanofsky +- S. Matthew English +- Steven +- Suhas Daftuar +- UdjinM6 +- Wladimir J. van der Laan +- wodry As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). From 7201dd7732fa69b498b1d647c66c2460af9bed7b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 19 Dec 2016 13:14:01 +0000 Subject: [PATCH 86/91] qt: Pre-rc1 translations update --- src/qt/bitcoinstrings.cpp | 8 +- src/qt/locale/bitcoin_ca.ts | 768 ++++++- src/qt/locale/bitcoin_ca_ES.ts | 774 ++++++- src/qt/locale/bitcoin_cs.ts | 1406 +++++++++++- src/qt/locale/bitcoin_de.ts | 390 +++- src/qt/locale/bitcoin_en.ts | 116 +- src/qt/locale/bitcoin_en_GB.ts | 112 +- src/qt/locale/bitcoin_es.ts | 1050 ++++++++- src/qt/locale/bitcoin_es_ES.ts | 3773 ++++++++++++++++++++++++++++++-- src/qt/locale/bitcoin_et.ts | 886 +++++++- src/qt/locale/bitcoin_fa.ts | 322 ++- src/qt/locale/bitcoin_fr.ts | 1176 +++++++++- src/qt/locale/bitcoin_it_IT.ts | 10 +- src/qt/locale/bitcoin_ko_KR.ts | 28 + src/qt/locale/bitcoin_ku_IQ.ts | 72 + src/qt/locale/bitcoin_pl.ts | 262 ++- src/qt/locale/bitcoin_pt_BR.ts | 1276 ++++++++++- src/qt/locale/bitcoin_pt_PT.ts | 8 + src/qt/locale/bitcoin_sk.ts | 28 +- src/qt/locale/bitcoin_sv.ts | 219 +- src/qt/locale/bitcoin_ta.ts | 20 + src/qt/locale/bitcoin_vi_VN.ts | 262 ++- src/qt/locale/bitcoin_zh_CN.ts | 853 +++++++- 23 files changed, 13347 insertions(+), 472 deletions(-) diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index b64ae5c70..7f90a51c5 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -145,6 +145,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Set the number of script verification threads (%u to %d, 0 = auto, <0 = " "leave that many cores free, default: %d)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Sets the serialization of raw transaction or block hex returned in non-" +"verbose mode, non-segwit(0) or segwit(1) (default: %d)"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Support filtering of blocks and transaction with bloom filters (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "" "The block database contains a block which appears to be from the future. " @@ -201,8 +204,8 @@ 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", "" -"Whitelist peers connecting from the given netmask or IP address. Can be " -"specified multiple times."), +"Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR " +"notated network (e.g. 1.2.3.0/24). Can be specified multiple times."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Whitelisted peers cannot be DoS banned and their transactions are always " "relayed, even if they are already in the mempool, useful e.g. for a gateway"), @@ -275,6 +278,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=: '%s' ( QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most unconnectable transactions in memory (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Keep the transaction memory pool below megabytes (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Keypool ran out, please call keypoolrefill first"), QT_TRANSLATE_NOOP("bitcoin-core", "Listen for JSON-RPC connections on (default: %u or testnet: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on (default: %u or testnet: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."), diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts index 355cd4418..c4cb86d82 100644 --- a/src/qt/locale/bitcoin_ca.ts +++ b/src/qt/locale/bitcoin_ca.ts @@ -41,10 +41,78 @@ &Delete &Elimina - + + Choose the address to send coins to + Trieu l'adreça on enviar les monedes + + + Choose the address to receive coins with + Trieu l'adreça on rebre les monedes + + + C&hoose + &Tria + + + Sending addresses + Adreces d'enviament + + + Receiving addresses + Adreces de recepció + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + 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. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Aquestes són les vostres adreces Bitcoin per rebre pagaments. Es recomana utilitzar una adreça nova de recepció per a cada transacció. + + + &Copy Address + &Copia l'adreça + + + Copy &Label + Copia l'eti&queta + + + &Edit + &Edita + + + Export Address List + Exporta la llista d'adreces + + + Comma separated file (*.csv) + Fitxer separat per comes (*.csv) + + + Exporting Failed + L'exportació ha fallat + + + There was an error trying to save the address list to %1. Please try again. + S'ha produït un error en desar la llista d'adreces a %1. Torneu-ho a provar. + + AddressTableModel - + + Label + Etiqueta + + + Address + Adreça + + + (no label) + (sense etiqueta) + + AskPassphraseDialog @@ -63,7 +131,95 @@ Repeat new passphrase Repetiu la nova contrasenya - + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Introduïu la contrasenya nova al moneder.<br/>Utilitzeu una contrasenya de <b>deu o més caràcters aleatoris</b>, o <b>vuit o més paraules</b>. + + + Encrypt wallet + Encripta el moneder + + + This operation needs your wallet passphrase to unlock the wallet. + Aquesta operació requereix la contrasenya del moneder per a desbloquejar-lo. + + + Unlock wallet + Desbloqueja el moneder + + + This operation needs your wallet passphrase to decrypt the wallet. + Aquesta operació requereix la contrasenya del moneder per desencriptar-lo. + + + Decrypt wallet + Desencripta el moneder + + + Change passphrase + Canvia la contrasenya + + + Enter the old passphrase and new passphrase to the wallet. + Introduïu la contrasenya antiga i la contrasenya nova al moneder. + + + Confirm wallet encryption + Confirma l'encriptació del moneder + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Avís: si encripteu el vostre moneder i perdeu la contrasenya, <b>PERDREU TOTS ELS VOSTRES BITCOINS</b>! + + + Are you sure you wish to encrypt your wallet? + Esteu segur que voleu encriptar el vostre moneder? + + + Wallet encrypted + Moneder encriptat + + + %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + Ara es tancarà el %1 per finalitzar el procés d'encriptació. Recordeu que encriptar el vostre moneder no garanteix que les vostres bitcoins no puguin ser robades per programari maliciós que infecti l'ordinador. + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + IMPORTANT: Tota copia de seguretat que hàgiu realitzat hauria de ser reemplaçada pel, recentment generat, fitxer encriptat del moneder. Per motius de seguretat, les còpies de seguretat anteriors del fitxer de moneder no encriptat esdevindran inusables tan aviat com començar a utilitzar el nou moneder encriptat. + + + Wallet encryption failed + L'encriptació del moneder ha fallat + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + L'encriptació del moneder ha fallat per un error intern. El moneder no ha estat encriptat. + + + The supplied passphrases do not match. + Les contrasenyes introduïdes no coincideixen. + + + Wallet unlock failed + El desbloqueig del moneder ha fallat + + + The passphrase entered for the wallet decryption was incorrect. + La contrasenya introduïda per a desencriptar el moneder és incorrecta. + + + Wallet decryption failed + La desencriptació del moneder ha fallat + + + Wallet passphrase was successfully changed. + La contrasenya del moneder ha estat modificada correctament. + + + Warning: The Caps Lock key is on! + Avís: Les lletres majúscules estan activades! + + BanTableModel @@ -113,6 +269,14 @@ Quit application Surt de l'aplicació + + &About %1 + Qu&ant al %1 + + + Show information about %1 + Mosta informació sobre el %1 + About &Qt Quant a &Qt @@ -125,6 +289,10 @@ &Options... &Opcions... + + Modify configuration options for %1 + Modifica les opcions de configuració de %1 + &Encrypt Wallet... &Encripta el moneder... @@ -143,7 +311,7 @@ &Receiving addresses... - Adreces de &recepció + Adreces de &recepció... Open &URI... @@ -253,6 +421,14 @@ %n active connection(s) to Bitcoin network %n connexió activa a la xarxa Bitcoin%n connexions actives a la xarxa Bitcoin + + Indexing blocks on disk... + S'estan indexant els blocs al disc... + + + Processing blocks on disk... + S'estan processant els blocs al disc... + No block source available... No hi ha cap font de bloc disponible... @@ -309,6 +485,14 @@ Up to date Al dia + + Show the %1 help message to get a list with possible Bitcoin command-line options + Mostra el missatge d'ajuda del %1 per obtenir una llista amb les possibles opcions de línia d'ordres de Bitcoin + + + %1 client + Client de %1 + Catching up... S'està posant al dia ... @@ -438,7 +622,143 @@ Priority Prioritat - + + Copy address + Copia l'adreça + + + Copy label + Copia l'etiqueta + + + Copy amount + Copia l'import + + + Copy transaction ID + Copia l'ID de transacció + + + Copy quantity + Copia la quantitat + + + Copy fee + Copia la comissió + + + Copy after fee + Copia la comissió posterior + + + Copy bytes + Copia els bytes + + + Copy priority + Copia la prioritat + + + Copy dust + Copia el polsim + + + Copy change + Copia el canvi + + + highest + el més alt + + + higher + més alt + + + high + alt + + + medium-high + mig-alt + + + medium + mig + + + low-medium + baix-mig + + + low + baix + + + lower + més baix + + + lowest + el més baix + + + (%1 locked) + (%1 bloquejada) + + + none + cap + + + yes + + + + no + no + + + This label turns red if the transaction size is greater than 1000 bytes. + Aquesta etiqueta es torna en vermell si la transacció és superior a 1000 bytes. + + + This means a fee of at least %1 per kB is required. + Això comporta que cal una comissió d'almenys %1 per kB. + + + Can vary +/- 1 byte per input. + Pot variar +/- 1 byte per entrada. + + + Transactions with higher priority are more likely to get included into a block. + Les transaccions amb una major prioritat són més propenses a ser incloses en un bloc. + + + This label turns red if the priority is smaller than "medium". + Aquesta etiqueta es torna en vermell si la propietat és inferior que la «mitjana». + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Aquesta etiqueta es torna vermella si cap recipient rep un import inferior al llindar de polsim actual. + + + Can vary +/- %1 satoshi(s) per input. + Pot variar en +/- %1 satoshi(s) per entrada. + + + (no label) + (sense etiqueta) + + + change from %1 (%2) + canvia de %1 (%2) + + + (change) + (canvia) + + EditAddressDialog @@ -461,7 +781,39 @@ &Address &Adreça - + + New receiving address + Nova adreça de recepció + + + New sending address + Nova adreça d'enviament + + + Edit receiving address + Edita l'adreça de recepció + + + Edit sending address + Edita l'adreça d'enviament + + + The entered address "%1" is not a valid Bitcoin address. + L'adreça introduïda «%1» no és una adreça de Bitcoin vàlida. + + + The entered address "%1" is already in the address book. + L'adreça introduïda «%1» ja és present a la llibreta d'adreces. + + + Could not unlock wallet. + No s'ha pogut desbloquejar el moneder. + + + New key generation failed. + Ha fallat la generació d'una clau nova. + + FreespaceChecker @@ -495,6 +847,10 @@ (%1-bit) (%1-bit) + + About %1 + Quant al %1 + Command-line options Opcions de línia d'ordres @@ -531,12 +887,28 @@ Show splash screen on startup (default: %u) Mostra la pantalla de benvinguda a l'inici (per defecte: %u) - + + Reset all settings changed in the GUI + Reinicialitza tots els canvis de configuració fets des de la interfície gràfica + + Intro Welcome - Us donem la benviguda + Us donem la benvinguda + + + Welcome to %1. + Us donem la benvinguda a %1. + + + As this is the first time the program is launched, you can choose where %1 will store its data. + Com és la primera vegada que s'executa el programa, podeu triar on %1 emmagatzemarà les dades. + + + %1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + %1 baixarà i emmagatzemarà una còpia de la cadena de blocs de Bitcoin. Com a mínim %2GB de dades s'emmagatzemaran en aquest directori, i augmentarà al llarg del temps. El moneder també s'emmagatzemarà en aquest directori. Use the default data directory @@ -581,7 +953,11 @@ Select payment request file Selecciona un fitxer de sol·licitud de pagament - + + Select payment request file to open + Seleccioneu el fitxer de sol·licitud de pagament per obrir + + OptionsDialog @@ -592,6 +968,14 @@ &Main &Principal + + Automatically start %1 after logging in to the system. + Inicieu %1 automàticament després d'entrar en el sistema. + + + &Start %1 on system login + &Inicia %1 en l'entrada al sistema + Size of &database cache Mida de la memòria cau de la base de &dades @@ -728,6 +1112,14 @@ &Window &Finestra + + &Hide the icon from the system tray. + Ama&ga la icona de la safata del sistema. + + + Hide tray icon + Amaga la icona de la safata + Show only a tray icon after minimizing the window. Mostra només la icona de la barra en minimitzar la finestra. @@ -748,6 +1140,10 @@ User Interface &language: &Llengua de la interfície d'usuari: + + The user interface language can be set here. This setting will take effect after restarting %1. + Aquí es pot definir la llengua de la interfície d'usuari. Aquest paràmetre tindrà efecte en reiniciar el %1. + &Unit to show amounts in: &Unitats per mostrar els imports en: @@ -874,7 +1270,27 @@ PaymentServer - + + Payment request error + Error de la sol·licitud de pagament + + + Cannot start bitcoin: click-to-pay handler + No es pot iniciar bitcoin: controlador click-to-pay + + + URI handling + Gestió d'URI + + + Network request error + Error en la sol·licitud de xarxa + + + Payment acknowledged + Pagament reconegut + + PeerTableModel @@ -931,7 +1347,23 @@ QRImageWidget - + + &Save Image... + De&sa la imatge... + + + &Copy Image + &Copia la imatge + + + Save QR Code + Desa el codi QR + + + PNG Image (*.png) + Imatge PNG (*.png) + + RPCConsole @@ -958,6 +1390,10 @@ Using BerkeleyDB version Utilitzant BerkeleyDB versió + + Datadir + Datadir + Startup time &Temps d'inici @@ -1273,7 +1709,15 @@ Remove Esborra - + + Copy label + Copia l'etiqueta + + + Copy amount + Copia l'import + + ReceiveRequestDialog @@ -1292,10 +1736,66 @@ &Save Image... De&sa la imatge... + + Request payment to %1 + Sol·licita un pagament a %1 + + + Payment information + Informació de pagament + + + URI + URI + + + Address + Adreça + + + Amount + Import + + + Label + Etiqueta + + + Message + Missatge + RecentRequestsTableModel - + + Date + Data + + + Label + Etiqueta + + + Message + Missatge + + + (no label) + (sense etiqueta) + + + (no message) + (sense missatge) + + + (no amount requested) + (no s'ha sol·licitat import) + + + Requested + Sol·licitat + + SendCoinsDialog @@ -1446,7 +1946,79 @@ S&end E&nvia - + + Copy quantity + Copia la quantitat + + + Copy amount + Copia l'import + + + Copy fee + Copia la comissió + + + Copy after fee + Copia la comissió posterior + + + Copy bytes + Copia els bytes + + + Copy priority + Copia la prioritat + + + Copy dust + Copia el polsim + + + Copy change + Copia el canvi + + + Total Amount %1 + Import total %1 + + + or + o + + + Confirm send coins + Confirma l'enviament de monedes + + + The recipient address is not valid. Please recheck. + L'adreça del destinatari no és vàlida. Torneu-la a comprovar. + + + The amount to pay must be larger than 0. + L'import a pagar ha de ser major que 0. + + + The amount exceeds your balance. + L'import supera el vostre balanç. + + + The total exceeds your balance when the %1 transaction fee is included. + El total excedeix el vostre balanç quan s'afegeix la comissió a la transacció %1. + + + Duplicate address found: addresses should only be used once each. + S'ha trobat una adreça duplicada: les adreces només s'haurien d'utilitzar una vegada cada una. + + + Transaction creation failed! + La creació de la transacció ha fallat! + + + (no label) + (sense etiqueta) + + SendCoinsEntry @@ -1639,6 +2211,74 @@ TransactionDesc + + Status + Estat + + + Date + Data + + + Source + Font + + + Generated + Generada + + + From + De + + + unknown + desconegut + + + To + A + + + own address + adreça pròpia + + + Debit + Dèbit + + + Total debit + Dèbit total + + + Total credit + Crèdit total + + + Transaction fee + Comissió de transacció + + + Net amount + Import net + + + Message + Missatge + + + Comment + Comentari + + + Transaction ID + ID de la transacció + + + Amount + Import + TransactionDescDialog @@ -1649,9 +2289,109 @@ TransactionTableModel + + Date + Data + + + Type + Tipus + + + Label + Etiqueta + + + Offline + Fora de línia + + + Unconfirmed + Sense confirmar + + + Abandoned + Abandonada + + + Received with + Rebuda amb + + + Received from + Rebuda de + + + Sent to + Enviada a + + + Payment to yourself + Pagament a un mateix + + + Mined + Minada + + + (no label) + (sense etiqueta) + TransactionView + + Received with + Rebuda amb + + + Sent to + Enviada a + + + Mined + Minada + + + Copy address + Copia l'adreça + + + Copy label + Copia l'etiqueta + + + Copy amount + Copia l'import + + + Copy transaction ID + Copia l'ID de transacció + + + Comma separated file (*.csv) + Fitxer separat per comes (*.csv) + + + Date + Data + + + Type + Tipus + + + Label + Etiqueta + + + Address + Adreça + + + Exporting Failed + L'exportació ha fallat + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts index 976881531..410b6e616 100644 --- a/src/qt/locale/bitcoin_ca_ES.ts +++ b/src/qt/locale/bitcoin_ca_ES.ts @@ -41,10 +41,78 @@ &Delete &Elimina - + + Choose the address to send coins to + Trieu l'adreça on enviar les monedes + + + Choose the address to receive coins with + Trieu l'adreça on rebre les monedes + + + C&hoose + &Tria + + + Sending addresses + Adreces d'enviament + + + Receiving addresses + Adreces de recepció + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + 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. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Aquestes són les vostres adreces Bitcoin per rebre pagaments. Es recomana utilitzar una adreça nova de recepció per a cada transacció. + + + &Copy Address + &Copia l'adreça + + + Copy &Label + Copia l'eti&queta + + + &Edit + &Edita + + + Export Address List + Exporta la llista d'adreces + + + Comma separated file (*.csv) + Fitxer separat per comes (*.csv) + + + Exporting Failed + L'exportació ha fallat + + + There was an error trying to save the address list to %1. Please try again. + S'ha produït un error en desar la llista d'adreces a %1. Torneu-ho a provar. + + AddressTableModel - + + Label + Etiqueta + + + Address + Adreça + + + (no label) + (sense etiqueta) + + AskPassphraseDialog @@ -63,7 +131,95 @@ Repeat new passphrase Repetiu la nova contrasenya - + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Introduïu la contrasenya nova al moneder.<br/>Utilitzeu una contrasenya de <b>deu o més caràcters aleatoris</b>, o <b>vuit o més paraules</b>. + + + Encrypt wallet + Encripta el moneder + + + This operation needs your wallet passphrase to unlock the wallet. + Aquesta operació requereix la contrasenya del moneder per a desbloquejar-lo. + + + Unlock wallet + Desbloqueja el moneder + + + This operation needs your wallet passphrase to decrypt the wallet. + Aquesta operació requereix la contrasenya del moneder per desencriptar-lo. + + + Decrypt wallet + Desencripta el moneder + + + Change passphrase + Canvia la contrasenya + + + Enter the old passphrase and new passphrase to the wallet. + Introduïu la contrasenya antiga i la contrasenya nova al moneder. + + + Confirm wallet encryption + Confirma l'encriptació del moneder + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Avís: si encripteu el vostre moneder i perdeu la contrasenya, <b>PERDREU TOTS ELS VOSTRES BITCOINS</b>! + + + Are you sure you wish to encrypt your wallet? + Esteu segur que voleu encriptar el vostre moneder? + + + Wallet encrypted + Moneder encriptat + + + %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + Ara es tancarà el %1 per finalitzar el procés d'encriptació. Recordeu que encriptar el vostre moneder no garanteix que les vostres bitcoins no puguin ser robades per programari maliciós que infecti l'ordinador. + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + IMPORTANT: Tota copia de seguretat que hàgiu realitzat hauria de ser reemplaçada pel, recentment generat, fitxer encriptat del moneder. Per motius de seguretat, les còpies de seguretat anteriors del fitxer de moneder no encriptat esdevindran inusables tan aviat com començar a utilitzar el nou moneder encriptat. + + + Wallet encryption failed + L'encriptació del moneder ha fallat + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + L'encriptació del moneder ha fallat per un error intern. El moneder no ha estat encriptat. + + + The supplied passphrases do not match. + Les contrasenyes introduïdes no coincideixen. + + + Wallet unlock failed + El desbloqueig del moneder ha fallat + + + The passphrase entered for the wallet decryption was incorrect. + La contrasenya introduïda per a desencriptar el moneder és incorrecta. + + + Wallet decryption failed + La desencriptació del moneder ha fallat + + + Wallet passphrase was successfully changed. + La contrasenya del moneder ha estat modificada correctament. + + + Warning: The Caps Lock key is on! + Avís: Les lletres majúscules estan activades! + + BanTableModel @@ -113,6 +269,14 @@ Quit application Surt de l'aplicació + + &About %1 + Qu&ant al %1 + + + Show information about %1 + Mosta informació sobre el %1 + About &Qt Quant a &Qt @@ -125,6 +289,10 @@ &Options... &Opcions... + + Modify configuration options for %1 + Modifica les opcions de configuració de %1 + &Encrypt Wallet... &Encripta el moneder... @@ -143,7 +311,7 @@ &Receiving addresses... - Adreces de &recepció + Adreces de &recepció... Open &URI... @@ -253,6 +421,14 @@ %n active connection(s) to Bitcoin network %n connexió activa a la xarxa Bitcoin%n connexions actives a la xarxa Bitcoin + + Indexing blocks on disk... + S'estan indexant els blocs al disc... + + + Processing blocks on disk... + S'estan processant els blocs al disc... + No block source available... No hi ha cap font de bloc disponible... @@ -309,6 +485,14 @@ Up to date Al dia + + Show the %1 help message to get a list with possible Bitcoin command-line options + Mostra el missatge d'ajuda del %1 per obtenir una llista amb les possibles opcions de línia d'ordres de Bitcoin + + + %1 client + Client de %1 + Catching up... S'està posant al dia ... @@ -438,7 +622,143 @@ Priority Prioritat - + + Copy address + Copia l'adreça + + + Copy label + Copia l'etiqueta + + + Copy amount + Copia l'import + + + Copy transaction ID + Copia l'ID de transacció + + + Copy quantity + Copia la quantitat + + + Copy fee + Copia la comissió + + + Copy after fee + Copia la comissió posterior + + + Copy bytes + Copia els bytes + + + Copy priority + Copia la prioritat + + + Copy dust + Copia el polsim + + + Copy change + Copia el canvi + + + highest + el més alt + + + higher + més alt + + + high + alt + + + medium-high + mig-alt + + + medium + mig + + + low-medium + baix-mig + + + low + baix + + + lower + més baix + + + lowest + el més baix + + + (%1 locked) + (%1 bloquejada) + + + none + cap + + + yes + + + + no + no + + + This label turns red if the transaction size is greater than 1000 bytes. + Aquesta etiqueta es torna en vermell si la transacció és superior a 1000 bytes. + + + This means a fee of at least %1 per kB is required. + Això comporta que cal una comissió d'almenys %1 per kB. + + + Can vary +/- 1 byte per input. + Pot variar +/- 1 byte per entrada. + + + Transactions with higher priority are more likely to get included into a block. + Les transaccions amb una major prioritat són més propenses a ser incloses en un bloc. + + + This label turns red if the priority is smaller than "medium". + Aquesta etiqueta es torna en vermell si la propietat és inferior que la «mitjana». + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Aquesta etiqueta es torna vermella si cap recipient rep un import inferior al llindar de polsim actual. + + + Can vary +/- %1 satoshi(s) per input. + Pot variar en +/- %1 satoshi(s) per entrada. + + + (no label) + (sense etiqueta) + + + change from %1 (%2) + canvia de %1 (%2) + + + (change) + (canvia) + + EditAddressDialog @@ -461,7 +781,39 @@ &Address &Adreça - + + New receiving address + Nova adreça de recepció + + + New sending address + Nova adreça d'enviament + + + Edit receiving address + Edita l'adreça de recepció + + + Edit sending address + Edita l'adreça d'enviament + + + The entered address "%1" is not a valid Bitcoin address. + L'adreça introduïda «%1» no és una adreça de Bitcoin vàlida. + + + The entered address "%1" is already in the address book. + L'adreça introduïda «%1» ja és present a la llibreta d'adreces. + + + Could not unlock wallet. + No s'ha pogut desbloquejar el moneder. + + + New key generation failed. + Ha fallat la generació d'una clau nova. + + FreespaceChecker @@ -495,6 +847,10 @@ (%1-bit) (%1-bit) + + About %1 + Quant al %1 + Command-line options Opcions de línia d'ordres @@ -531,12 +887,28 @@ Show splash screen on startup (default: %u) Mostra la pantalla de benvinguda a l'inici (per defecte: %u) - + + Reset all settings changed in the GUI + Reinicialitza tots els canvis de configuració fets des de la interfície gràfica + + Intro Welcome - Us donem la benviguda + Us donem la benvinguda + + + Welcome to %1. + Us donem la benvinguda a %1. + + + As this is the first time the program is launched, you can choose where %1 will store its data. + Com és la primera vegada que s'executa el programa, podeu triar on %1 emmagatzemarà les dades. + + + %1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + %1 baixarà i emmagatzemarà una còpia de la cadena de blocs de Bitcoin. Com a mínim %2GB de dades s'emmagatzemaran en aquest directori, i augmentarà al llarg del temps. El moneder també s'emmagatzemarà en aquest directori. Use the default data directory @@ -581,7 +953,11 @@ Select payment request file Selecciona un fitxer de sol·licitud de pagament - + + Select payment request file to open + Seleccioneu el fitxer de sol·licitud de pagament per obrir + + OptionsDialog @@ -592,6 +968,14 @@ &Main &Principal + + Automatically start %1 after logging in to the system. + Inicieu %1 automàticament després d'entrar en el sistema. + + + &Start %1 on system login + &Inicia %1 en l'entrada al sistema + Size of &database cache Mida de la memòria cau de la base de &dades @@ -728,6 +1112,14 @@ &Window &Finestra + + &Hide the icon from the system tray. + Ama&ga la icona de la safata del sistema. + + + Hide tray icon + Amaga la icona de la safata + Show only a tray icon after minimizing the window. Mostra només la icona de la barra en minimitzar la finestra. @@ -748,6 +1140,10 @@ User Interface &language: &Llengua de la interfície d'usuari: + + The user interface language can be set here. This setting will take effect after restarting %1. + Aquí es pot definir la llengua de la interfície d'usuari. Aquest paràmetre tindrà efecte en reiniciar el %1. + &Unit to show amounts in: &Unitats per mostrar els imports en: @@ -874,7 +1270,27 @@ PaymentServer - + + Payment request error + Error de la sol·licitud de pagament + + + Cannot start bitcoin: click-to-pay handler + No es pot iniciar bitcoin: controlador click-to-pay + + + URI handling + Gestió d'URI + + + Network request error + Error en la sol·licitud de xarxa + + + Payment acknowledged + Pagament reconegut + + PeerTableModel @@ -931,7 +1347,23 @@ QRImageWidget - + + &Save Image... + De&sa la imatge... + + + &Copy Image + &Copia la imatge + + + Save QR Code + Desa el codi QR + + + PNG Image (*.png) + Imatge PNG (*.png) + + RPCConsole @@ -958,6 +1390,10 @@ Using BerkeleyDB version Utilitzant BerkeleyDB versió + + Datadir + Datadir + Startup time &Temps d'inici @@ -1273,7 +1709,15 @@ Remove Esborra - + + Copy label + Copia l'etiqueta + + + Copy amount + Copia l'import + + ReceiveRequestDialog @@ -1292,10 +1736,66 @@ &Save Image... De&sa la imatge... + + Request payment to %1 + Sol·licita un pagament a %1 + + + Payment information + Informació de pagament + + + URI + URI + + + Address + Adreça + + + Amount + Import + + + Label + Etiqueta + + + Message + Missatge + RecentRequestsTableModel - + + Date + Data + + + Label + Etiqueta + + + Message + Missatge + + + (no label) + (sense etiqueta) + + + (no message) + (sense missatge) + + + (no amount requested) + (no s'ha sol·licitat import) + + + Requested + Sol·licitat + + SendCoinsDialog @@ -1446,7 +1946,79 @@ S&end E&nvia - + + Copy quantity + Copia la quantitat + + + Copy amount + Copia l'import + + + Copy fee + Copia la comissió + + + Copy after fee + Copia la comissió posterior + + + Copy bytes + Copia els bytes + + + Copy priority + Copia la prioritat + + + Copy dust + Copia el polsim + + + Copy change + Copia el canvi + + + Total Amount %1 + Import total %1 + + + or + o + + + Confirm send coins + Confirma l'enviament de monedes + + + The recipient address is not valid. Please recheck. + L'adreça del destinatari no és vàlida. Torneu-la a comprovar. + + + The amount to pay must be larger than 0. + L'import a pagar ha de ser major que 0. + + + The amount exceeds your balance. + L'import supera el vostre balanç. + + + The total exceeds your balance when the %1 transaction fee is included. + El total excedeix el vostre balanç quan s'afegeix la comissió a la transacció %1. + + + Duplicate address found: addresses should only be used once each. + S'ha trobat una adreça duplicada: les adreces només s'haurien d'utilitzar una vegada cada una. + + + Transaction creation failed! + La creació de la transacció ha fallat! + + + (no label) + (sense etiqueta) + + SendCoinsEntry @@ -1639,6 +2211,74 @@ TransactionDesc + + Status + Estat + + + Date + Data + + + Source + Font + + + Generated + Generada + + + From + De + + + unknown + desconegut + + + To + A + + + own address + adreça pròpia + + + Debit + Dèbit + + + Total debit + Dèbit total + + + Total credit + Crèdit total + + + Transaction fee + Comissió de transacció + + + Net amount + Import net + + + Message + Missatge + + + Comment + Comentari + + + Transaction ID + ID de la transacció + + + Amount + Import + TransactionDescDialog @@ -1649,9 +2289,109 @@ TransactionTableModel + + Date + Data + + + Type + Tipus + + + Label + Etiqueta + + + Offline + Fora de línia + + + Unconfirmed + Sense confirmar + + + Abandoned + Abandonada + + + Received with + Rebuda amb + + + Received from + Rebuda de + + + Sent to + Enviada a + + + Payment to yourself + Pagament a un mateix + + + Mined + Minada + + + (no label) + (sense etiqueta) + TransactionView + + Received with + Rebuda amb + + + Sent to + Enviada a + + + Mined + Minada + + + Copy address + Copia l'adreça + + + Copy label + Copia l'etiqueta + + + Copy amount + Copia l'import + + + Copy transaction ID + Copia l'ID de transacció + + + Comma separated file (*.csv) + Fitxer separat per comes (*.csv) + + + Date + Data + + + Type + Tipus + + + Label + Etiqueta + + + Address + Adreça + + + Exporting Failed + L'exportació ha fallat + UnitDisplayStatusBarControl @@ -1737,7 +2477,11 @@ Bitcoin Core - Nucli de Bitcoin + Bitcoin Core + + + -fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available. + -fallbackfee és molt elevat. Aquesta és la comissió de transacció que podeu pagar quan les estimacions de comissions no estan disponibles. Bind to given address and always listen on it. Use [host]:port notation for IPv6 diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts index 449e67dd3..02e959d01 100644 --- a/src/qt/locale/bitcoin_cs.ts +++ b/src/qt/locale/bitcoin_cs.ts @@ -15,7 +15,7 @@ Copy the currently selected address to the system clipboard - Zkopíruj aktuálně vybranou adresu do systémové schránky + Zkopíruj tuto adresu do systémové schránky &Copy @@ -27,7 +27,7 @@ Delete the currently selected address from the list - Smaž zvolenou adresu ze seznamu + Smaž tuto adresu ze seznamu Export the data in the current tab to a file @@ -41,10 +41,78 @@ &Delete S&maž - + + Choose the address to send coins to + Zvol adresu, na kterou pošleš mince + + + Choose the address to receive coins with + Zvol adres na příjem mincí + + + C&hoose + &Zvol + + + Sending addresses + Odesílací adresy + + + Receiving addresses + Přijímací adresy + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + 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. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Tohle jsou tvé Bitcoinové adresy pro příjem plateb. Nezapomeň si pro každou transakci vždy vygenerovat novou adresu. + + + &Copy Address + &Kopíruj adresu + + + Copy &Label + Kopíruj &označení + + + &Edit + &Uprav + + + Export Address List + Export seznamu adres + + + Comma separated file (*.csv) + Formát CSV (*.csv) + + + Exporting Failed + Exportování selhalo + + + There was an error trying to save the address list to %1. Please try again. + Při ukládání seznamu adres do %1 se přihodila nějaká chyba. Zkus to prosím znovu. + + AddressTableModel - + + Label + Označení + + + Address + Adresa + + + (no label) + (bez označení) + + AskPassphraseDialog @@ -63,10 +131,106 @@ Repeat new passphrase Totéž heslo ještě jednou - + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Zadej nové heslo k peněžence.<br/>Použij <b>alespoň deset náhodných znaků</b> nebo <b>alespoň osm slov</b>. + + + Encrypt wallet + Zašifruj peněženku + + + This operation needs your wallet passphrase to unlock the wallet. + K provedení této operace musíš zadat heslo k peněžence, aby se mohla odemknout. + + + Unlock wallet + Odemkni peněženku + + + This operation needs your wallet passphrase to decrypt the wallet. + K provedení této operace musíš zadat heslo k peněžence, aby se mohla dešifrovat. + + + Decrypt wallet + Dešifruj peněženku + + + Change passphrase + Změň heslo + + + Enter the old passphrase and new passphrase to the wallet. + Zadej staré a nové heslo k peněžence. + + + Confirm wallet encryption + Potvrď zašifrování peněženky + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Upozornění: Pokud si zašifruješ peněženku a ztratíš či zapomeneš heslo, <b>PŘIJDEŠ O VŠECHNY BITCOINY</b>! + + + Are you sure you wish to encrypt your wallet? + Jsi si jistý, že chceš peněženku zašifrovat? + + + Wallet encrypted + Peněženka je zašifrována + + + %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + %1 se teď ukončí, aby dokončil zašifrování. Pamatuj však, že pouhé zašifrování peněženky nemůže zabránit krádeži tvých bitcoinů malwarem, kterým se může počítač nakazit. + + + 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. + DŮLEŽITÉ: Všechny předchozí zálohy peněženky by měly být nahrazeny nově vygenerovanou, zašifrovanou peněženkou. Z bezpečnostních důvodů budou předchozí zálohy nešifrované peněženky nepoužitelné, jakmile začneš používat novou zašifrovanou peněženku. + + + Wallet encryption failed + Zašifrování peněženky selhalo + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Zašifrování peněženky selhalo kvůli vnitřní chybě. Tvá peněženka tedy nebyla zašifrována. + + + The supplied passphrases do not match. + Zadaná hesla nejsou shodná. + + + Wallet unlock failed + Nepodařilo se odemknout peněženku + + + The passphrase entered for the wallet decryption was incorrect. + Nezadal jsi správné heslo pro dešifrování peněženky. + + + Wallet decryption failed + Nepodařilo se dešifrovat peněženku + + + Wallet passphrase was successfully changed. + Heslo k peněžence bylo v pořádku změněno. + + + Warning: The Caps Lock key is on! + Upozornění: Caps Lock je zapnutý! + + BanTableModel - + + IP/Netmask + IP/Maska + + + Banned Until + Blokován do + + BitcoinGUI @@ -105,6 +269,14 @@ Quit application Ukonči aplikaci + + &About %1 + O &%1 + + + Show information about %1 + Zobraz informace o %1 + About &Qt O &Qt @@ -117,6 +289,10 @@ &Options... &Možnosti... + + Modify configuration options for %1 + Uprav nastavení %1 + &Encrypt Wallet... Zaši&fruj peněženku... @@ -245,6 +421,14 @@ %n active connection(s) to Bitcoin network %n aktivní spojení do Bitcoinové sítě%n aktivní spojení do Bitcoinové sítě%n aktivních spojení do Bitcoinové sítě + + Indexing blocks on disk... + Vytvářím index bloků na disku... + + + Processing blocks on disk... + Zpracovávám bloky na disku... + No block source available... Není dostupný žádný zdroj bloků... @@ -283,7 +467,7 @@ Transactions after this will not yet be visible. - Novější transakce zatím nejsou vidět. + Následné transakce ještě nebudou vidět. Error @@ -301,6 +485,14 @@ Up to date Aktuální + + Show the %1 help message to get a list with possible Bitcoin command-line options + Seznam argumentů Bitcoinu pro příkazovou řádku získáš v nápovědě %1 + + + %1 client + %1 klient + Catching up... Stahuji... @@ -430,7 +622,87 @@ Priority Priorita - + + Copy address + Kopíruj adresu + + + Copy label + Kopíruj její označení + + + Copy amount + Kopíruj částku + + + Copy transaction ID + Kopíruj ID transakce + + + Lock unspent + Zamkni neutracené + + + Unlock unspent + Odemkni k utracení + + + Copy quantity + Kopíruj počet + + + Copy fee + Kopíruj poplatek + + + Copy after fee + Kopíruj čistou částku + + + Copy bytes + Kopíruj bajty + + + Copy dust + Kopíruj prach + + + Copy change + Kopíruj drobné + + + (%1 locked) + (%1 zamčeno) + + + yes + ano + + + no + ne + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Popisek zčervená, pokud má některý příjemce obdržet částku menší, než je aktuální práh pro prach. + + + Can vary +/- %1 satoshi(s) per input. + Může se lišit o +/– %1 satoshi na každý vstup. + + + (no label) + (bez označení) + + + change from %1 (%2) + drobné z %1 (%2) + + + (change) + (drobné) + + EditAddressDialog @@ -453,7 +725,39 @@ &Address &Adresa - + + New receiving address + Nová přijímací adresa + + + New sending address + Nová odesílací adresa + + + Edit receiving address + Uprav přijímací adresu + + + Edit sending address + Uprav odesílací adresu + + + The entered address "%1" is not a valid Bitcoin address. + Zadaná adresa „%1“ není platná Bitcoinová adresa. + + + The entered address "%1" is already in the address book. + Zadaná adresa „%1“ už v adresáři je. + + + Could not unlock wallet. + Nemohu odemknout peněženku. + + + New key generation failed. + Nepodařilo se mi vygenerovat nový klíč. + + FreespaceChecker @@ -487,6 +791,10 @@ (%1-bit) (%1-bit) + + About %1 + O %1 + Command-line options Argumenty příkazové řádky @@ -523,13 +831,29 @@ Show splash screen on startup (default: %u) Zobrazit startovací obrazovku (výchozí: %u) - + + Reset all settings changed in the GUI + Vrátit všechny volby měněné v GUI na výchozí hodnoty + + Intro Welcome Vítej + + Welcome to %1. + Vítej v %1. + + + As this is the first time the program is launched, you can choose where %1 will store its data. + Tohle je poprvé, co spouštíš %1, takže si můžeš zvolit, kam bude ukládat svá data. + + + %1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + %1 bude stahovat kopii řetězce bloků. Proto bude potřeba do tohoto adresáře uložit nejméně %2 GB dat – toto číslo bude navíc v průběhu času růst. Tvá peněženka bude rovněž uložena v tomto adresáři. + Use the default data directory Použij výchozí adresář pro data @@ -573,7 +897,11 @@ Select payment request file Vyber soubor platebního požadavku - + + Select payment request file to open + Vyber soubor platebního požadavku k načtení + + OptionsDialog @@ -584,6 +912,14 @@ &Main &Hlavní + + Automatically start %1 after logging in to the system. + Automaticky spustí %1 po přihlášení do systému. + + + &Start %1 on system login + S&pustit %1 po přihlášení do systému + Size of &database cache Velikost &databázové cache @@ -622,7 +958,7 @@ Active command-line options that override above options: - Aktivní argumenty z příkazové řádky, které mají přednost před nastavením výše: + Aktivní argumenty z příkazové řádky, které přetloukly tato nastavení: Reset all client options to default. @@ -690,7 +1026,7 @@ Used for reaching peers via: - Použije se k připojování k protějškům přes: + Použije se k připojování k protějskům přes: Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. @@ -720,6 +1056,14 @@ &Window O&kno + + &Hide the icon from the system tray. + Skryje ikonu, která se zobrazuje v panelu. + + + Hide tray icon + Skrýt &ikonu z panelu + Show only a tray icon after minimizing the window. Po minimalizaci okna zobrazí pouze ikonu v panelu. @@ -740,6 +1084,10 @@ User Interface &language: &Jazyk uživatelského rozhraní: + + The user interface language can be set here. This setting will take effect after restarting %1. + Tady lze nastavit jazyk uživatelského rozhraní. Nastavení se projeví až po restartování %1. + &Unit to show amounts in: Je&dnotka pro částky: @@ -754,7 +1102,7 @@ &OK - &Použít + &Budiž &Cancel @@ -782,7 +1130,7 @@ This change would require a client restart. - Tato změna vyžaduje restart aplikace. + Tahle změna bude chtít restartovat klienta. The supplied proxy address is invalid. @@ -829,7 +1177,7 @@ Balances - Stav účtů + Stavy účtů Total: @@ -866,7 +1214,95 @@ PaymentServer - + + Payment request error + Chyba platebního požadavku + + + Cannot start bitcoin: click-to-pay handler + Nemůžu spustit bitcoin: obsluha click-to-pay + + + URI handling + Zpracování URI + + + Payment request fetch URL is invalid: %1 + Zdrojová URL platebního požadavku není platná: %1 + + + Invalid payment address %1 + Neplatná platební adresa %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + Nepodařilo se analyzovat URI! Důvodem může být neplatná Bitcoinová adresa nebo poškozené parametry URI. + + + Payment request file handling + Zpracování souboru platebního požadavku + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + Soubor platebního požadavku nejde přečíst nebo zpracovat! Příčinou může být špatný soubor platebního požadavku. + + + Payment request rejected + Platební požadavek byl odmítnut + + + Payment request network doesn't match client network. + Síť platebního požadavku neodpovídá síti klienta. + + + Payment request expired. + Platební požadavek vypršel. + + + Payment request is not initialized. + Platební požadavek není zahájený. + + + Unverified payment requests to custom payment scripts are unsupported. + Neověřené platební požadavky k uživatelským platebním skriptům nejsou podporované. + + + Invalid payment request. + Neplatný platební požadavek. + + + Requested payment amount of %1 is too small (considered dust). + Požadovaná platební částka %1 je příliš malá (je považována za prach). + + + Refund from %1 + Vrácení peněz od %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Platební požadavek %1 je moc velký (%2 bajtů, povoleno %3 bajtů). + + + Error communicating with %1: %2 + Chyba při komunikaci s %1: %2 + + + Payment request cannot be parsed! + Platební požadavek je nečitelný! + + + Bad response from server %1 + Chybná odpověď ze serveru %1 + + + Network request error + Chyba síťového požadavku + + + Payment acknowledged + Platba potvrzena + + PeerTableModel @@ -923,12 +1359,28 @@ QRImageWidget - + + &Save Image... + &Ulož obrázek... + + + &Copy Image + &Kopíruj obrázek + + + Save QR Code + Ulož QR kód + + + PNG Image (*.png) + PNG obrázek (*.png) + + RPCConsole N/A - N/A + nedostupná informace Client version @@ -950,6 +1402,10 @@ Using BerkeleyDB version Používaná verze BerkeleyDB + + Datadir + Adresář s daty + Startup time Čas spuštění @@ -974,9 +1430,17 @@ Current number of blocks Aktuální počet bloků + + Memory Pool + Transakční zásobník + + + Current number of transactions + Aktuální množství transakcí + Memory usage - Využití paměti + Obsazenost paměti Received @@ -990,10 +1454,18 @@ &Peers &Protějšky + + Banned peers + Protějšky pod klatbou (blokované) + Select a peer to view detailed information. Vyber protějšek a uvidíš jeho detailní informace. + + Whitelisted + Vždy vítán + Direction Směr @@ -1003,19 +1475,43 @@ Verze - User Agent - Typ klienta + Starting Block + Počáteční blok - Services - Služby + Synced Headers + Aktuálně hlaviček - Ban Score - Skóre pro klatbu + Synced Blocks + Aktuálně bloků - Connection Time + User Agent + Typ klienta + + + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. + 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. + + + Decrease font size + Zmenšit písmo + + + Increase font size + Zvětšit písmo + + + Services + Služby + + + Ban Score + Skóre pro klatbu + + + Connection Time Doba spojení @@ -1030,6 +1526,14 @@ Ping Time Odezva + + The duration of a currently outstanding ping. + Jak dlouho už čekám na pong. + + + Ping Wait + Doba čekání na odezvu + Time Offset Časový posun @@ -1102,6 +1606,10 @@ &Unban Node &Zbavit uzel klatby + + Welcome to the %1 RPC console. + Vítej v RPC konzoli %1. + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. V historii se pohybuješ šipkami nahoru a dolů a pomocí <b>Ctrl-L</b> čistíš obrazovku. @@ -1229,7 +1737,19 @@ Remove Smazat - + + Copy label + Kopíruj její označení + + + Copy message + Kopíruj zprávu + + + Copy amount + Kopíruj částku + + ReceiveRequestDialog @@ -1248,10 +1768,74 @@ &Save Image... &Ulož obrázek... - + + Request payment to %1 + Platební požadavek: %1 + + + Payment information + Informace o platbě + + + URI + URI + + + Address + Adresa + + + Amount + Částka + + + Label + Označení + + + Message + Zpráva + + + Resulting URI too long, try to reduce the text for label / message. + Výsledná URI je příliš dlouhá, zkus zkrátit text označení/zprávy. + + + Error encoding URI into QR Code. + Chyba při kódování URI do QR kódu. + + RecentRequestsTableModel - + + Date + Datum + + + Label + Označení + + + Message + Zpráva + + + (no label) + (bez označení) + + + (no message) + (bez zprávy) + + + (no amount requested) + (bez požadované částky) + + + Requested + Požádáno + + SendCoinsDialog @@ -1402,7 +1986,111 @@ S&end Pošl&i - + + Copy quantity + Kopíruj počet + + + Copy amount + Kopíruj částku + + + Copy fee + Kopíruj poplatek + + + Copy after fee + Kopíruj čistou částku + + + Copy bytes + Kopíruj bajty + + + Copy dust + Kopíruj prach + + + Copy change + Kopíruj drobné + + + %1 to %2 + %1 pro %2 + + + Are you sure you want to send? + Jsi si jistý, že to chceš poslat? + + + added as transaction fee + přidán jako transakční poplatek + + + Total Amount %1 + Celková částka %1 + + + or + nebo + + + Confirm send coins + Potvrď odeslání mincí + + + The recipient address is not valid. Please recheck. + Adresa příjemce je neplatná – překontroluj ji prosím. + + + The amount to pay must be larger than 0. + Odesílaná částka musí být větší než 0. + + + The amount exceeds your balance. + Částka překračuje stav účtu. + + + The total exceeds your balance when the %1 transaction fee is included. + Celková částka při připočítání poplatku %1 překročí stav účtu. + + + Duplicate address found: addresses should only be used once each. + Zaznamenána duplicitní adresa: každá adresa by ale měla být použita vždy jen jednou. + + + Transaction creation failed! + Vytvoření transakce selhalo! + + + A fee higher than %1 is considered an absurdly high fee. + Poplatek vyšší než %1 je považován za absurdně vysoký. + + + Payment request expired. + Platební požadavek vypršel. + + + Pay only the required fee of %1 + Zaplatit pouze vyžadovaný poplatek %1 + + + Estimated to begin confirmation within %n block(s). + Potvrzování by podle odhadu mělo začít během %n bloku.Potvrzování by podle odhadu mělo začít během %n bloků.Potvrzování by podle odhadu mělo začít během %n bloků. + + + Warning: Invalid Bitcoin address + Upozornění: Neplatná Bitcoinová adresa + + + Warning: Unknown change address + Upozornění: Neznámá adresa pro drobné + + + (no label) + (bez označení) + + SendCoinsEntry @@ -1481,12 +2169,24 @@ Memo: Poznámka: - + + Enter a label for this address to add it to your address book + Zadej označení této adresy; obojí se ti pak uloží do adresáře + + SendConfirmationDialog - + + Yes + Ano + + ShutdownWindow + + %1 is shutting down... + %1 se ukončuje... + Do not shut down the computer until this window disappears. Nevypínej počítač, dokud toto okno nezmizí. @@ -1578,7 +2278,59 @@ Reset all verify message fields Vymaž všechna pole formuláře pro ověření zrávy - + + Click "Sign Message" to generate signature + Kliknutím na „Podepiš zprávu“ vygeneruješ podpis + + + The entered address is invalid. + Zadaná adresa je neplatná. + + + Please check the address and try again. + Zkontroluj ji prosím a zkus to pak znovu. + + + The entered address does not refer to a key. + Zadaná adresa nepasuje ke klíči. + + + Wallet unlock was cancelled. + Odemčení peněženky bylo zrušeno. + + + Private key for the entered address is not available. + Soukromý klíč pro zadanou adresu není dostupný. + + + Message signing failed. + Nepodařilo se podepsat zprávu. + + + Message signed. + Zpráva podepsána. + + + The signature could not be decoded. + Podpis nejde dekódovat. + + + Please check the signature and try again. + Zkontroluj ho prosím a zkus to pak znovu. + + + The signature did not match the message digest. + Podpis se neshoduje s hašem zprávy. + + + Message verification failed. + Nepodařilo se ověřit zprávu. + + + Message verified. + Zpráva ověřena. + + SplashScreen @@ -1595,20 +2347,456 @@ TransactionDesc - + + Open for %n more block(s) + Otevřeno pro %n další blokOtevřeno pro %n další blokyOtevřeno pro %n dalších bloků + + + Open until %1 + Otřevřeno dokud %1 + + + conflicted with a transaction with %1 confirmations + koliduje s transakcí o %1 konfirmacích + + + %1/offline + %1/offline + + + 0/unconfirmed, %1 + 0/nepotvrzeno, %1 + + + in memory pool + v transakčním zásobníku + + + not in memory pool + není ani v transakčním zásobníku + + + abandoned + zanechaná + + + %1/unconfirmed + %1/nepotvrzeno + + + %1 confirmations + %1 potvrzení + + + Status + Stav + + + , has not been successfully broadcast yet + , ještě nebylo rozesláno + + + , broadcast through %n node(s) + , rozesláno přes %n uzel, rozesláno přes %n uzly, rozesláno přes %n uzlů + + + Date + Datum + + + Source + Zdroj + + + Generated + Vygenerováno + + + From + Od + + + unknown + neznámo + + + To + Pro + + + own address + vlastní adresa + + + watch-only + sledovaná + + + label + označení + + + Credit + Příjem + + + matures in %n more block(s) + dozraje po %n blokudozraje po %n blocíchdozraje po %n blocích + + + not accepted + neakceptováno + + + Debit + Výdaj + + + Total debit + Celkové výdaje + + + Total credit + Celkové příjmy + + + Transaction fee + Transakční poplatek + + + Net amount + Čistá částka + + + Message + Zpráva + + + Comment + Komentář + + + Transaction ID + ID transakce + + + Output index + Pořadí výstupu + + + Merchant + Obchodník + + + 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. + Vygenerované mince musí čekat %1 bloků, než mohou být utraceny. Když jsi vygeneroval tenhle blok, tak byl rozposlán do sítě, aby byl přidán do řetězce bloků. Pokud se mu nepodaří dostat se do řetězce, změní se na „neakceptovaný“ a nepůjde utratit. To se občas může stát, pokud jiný uzel vygeneruje blok zhruba ve stejném okamžiku jako ty. + + + Debug information + Ladicí informace + + + Transaction + Transakce + + + Inputs + Vstupy + + + Amount + Částka + + + true + true + + + false + false + + TransactionDescDialog This pane shows a detailed description of the transaction Toto okno zobrazuje detailní popis transakce - + + Details for %1 + Podrobnosti o %1 + + TransactionTableModel - + + Date + Datum + + + Type + Typ + + + Label + Označení + + + Open for %n more block(s) + Otevřeno pro %n další blokOtevřeno pro %n další blokyOtevřeno pro %n dalších bloků + + + Open until %1 + Otřevřeno dokud %1 + + + Offline + Offline + + + Unconfirmed + Nepotvrzeno + + + Abandoned + Zanechaná + + + Confirming (%1 of %2 recommended confirmations) + Potvrzuje se (%1 z %2 doporučených potvrzení) + + + Confirmed (%1 confirmations) + Potvrzeno (%1 potvrzení) + + + Conflicted + V kolizi + + + Immature (%1 confirmations, will be available after %2) + Nedozráno (%1 potvrzení, dozraje při %2 potvrzeních) + + + This block was not received by any other nodes and will probably not be accepted! + Tento blok nedostal žádný jiný uzel a pravděpodobně nebude akceptován! + + + Generated but not accepted + Vygenerováno, ale neakceptováno + + + Received with + Přijato do + + + Received from + Přijato od + + + Sent to + Posláno na + + + Payment to yourself + Platba sama sobě + + + Mined + Vytěženo + + + watch-only + sledovací + + + (n/a) + (n/a) + + + (no label) + (bez označení) + + + Transaction status. Hover over this field to show number of confirmations. + Stav transakce. Najetím myši na toto políčko si zobrazíš počet potvrzení. + + + Date and time that the transaction was received. + Datum a čas přijetí transakce. + + + Type of transaction. + Druh transakce. + + + Whether or not a watch-only address is involved in this transaction. + Zda tato transakce zahrnuje i některou sledovanou adresu. + + + User-defined intent/purpose of the transaction. + Uživatelsky určený účel transakce. + + + Amount removed from or added to balance. + Částka odečtená z nebo přičtená k účtu. + + TransactionView - + + All + Vše + + + Today + Dnes + + + This week + Tento týden + + + This month + Tento měsíc + + + Last month + Minulý měsíc + + + This year + Letos + + + Range... + Rozsah... + + + Received with + Přijato + + + Sent to + Posláno + + + To yourself + Sám sobě + + + Mined + Vytěženo + + + Other + Ostatní + + + Enter address or label to search + Zadej adresu nebo označení pro její vyhledání + + + Min amount + Minimální částka + + + Abandon transaction + Zapomenout transakci + + + Copy address + Kopíruj adresu + + + Copy label + Kopíruj její označení + + + Copy amount + Kopíruj částku + + + Copy transaction ID + Kopíruj ID transakce + + + Copy raw transaction + Kopíruj surovou transakci + + + Copy full transaction details + Kopíruj kompletní podrobnosti o transakci + + + Edit label + Uprav označení + + + Show transaction details + Zobraz detaily transakce + + + Export Transaction History + Exportuj transakční historii + + + Comma separated file (*.csv) + Formát CSV (*.csv) + + + Confirmed + Potvrzeno + + + Watch-only + Sledovaná + + + Date + Datum + + + Type + Typ + + + Label + Označení + + + Address + Adresa + + + ID + ID + + + Exporting Failed + Exportování selhalo + + + There was an error trying to save the transaction history to %1. + Při ukládání transakční historie do %1 se přihodila nějaká chyba. + + + Exporting Successful + Úspěšně vyexportováno + + + The transaction history was successfully saved to %1. + Transakční historie byla v pořádku uložena do %1. + + + Range: + Rozsah: + + + to + + + UnitDisplayStatusBarControl @@ -1618,13 +2806,53 @@ WalletFrame - + + No wallet has been loaded. + Žádná peněženka se nenačetla. + + WalletModel - + + Send Coins + Pošli mince + + WalletView - + + &Export + &Export + + + Export the data in the current tab to a file + Exportuj data z tohoto panelu do souboru + + + Backup Wallet + Záloha peněženky + + + Wallet Data (*.dat) + Data peněženky (*.dat) + + + Backup Failed + Zálohování selhalo + + + There was an error trying to save the wallet data to %1. + Při ukládání peněženky do %1 se přihodila nějaká chyba. + + + Backup Successful + Úspěšně zazálohováno + + + The wallet data was successfully saved to %1. + Data z peněženky byla v pořádku uložena do %1. + + bitcoin-core @@ -1711,6 +2939,10 @@ Bind to given address and always listen on it. Use [host]:port notation for IPv6 Poslouchat na zadané adrese. Pro zápis IPv6 adresy použij notaci [adresa]:port + + Cannot obtain a lock on data directory %s. %s is probably already running. + Nedaří se mi získat zámek na datový adresář %s. %s pravděpodobně už jednou běží. + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup Smazat všechny transakce peněženky a při startu obnovit pouze relevantní části řetězce bloků pomocí -rescan @@ -1723,6 +2955,18 @@ Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) Spustit příkaz, když se objeví transakce týkající se peněženky (%s se v příkazu nahradí za TxID) + + Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s) + Horní hranice pro celkový poplatek (v %s) za jednu transakci z peněženky nebo jednu surovou transakci; příliš nízká hodnota může zmařit velké transakce (výchozí: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. + Zkontroluj, že máš v počítači správně nastavený datum a čas! Pokud jsou nastaveny špatně, %s nebude fungovat správně. + + + Please contribute if you find %s useful. Visit %s for further information about the software. + Prosíme, zapoj se nebo přispěj, pokud ti %s přijde užitečný. Více informací o programu je na %s. + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) Nastavení počtu vláken pro verifikaci skriptů (%u až %d, 0 = automaticky, <0 = nechat daný počet jader volný, výchozí: %d) @@ -1751,6 +2995,14 @@ Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. Vždy vítat protějšky připojující se z dané podsítě či IP adresy. Lze zadat i vícekrát. + + You need to rebuild the database using -reindex-chainstate to change -txindex + Je třeba přestavět databázi použitím -reindex-chainstate, aby bylo možné změnit -txindex + + + %s corrupt, salvage failed + %s je poškozen, jeho záchrana se nezdařila + -maxmempool must be at least %d MB -maxmempool musí být alespoň %d MB @@ -1763,10 +3015,18 @@ Append comment to the user agent string Připojit komentář k typu klienta + + Attempt to recover private keys from a corrupt wallet on startup + Pokusit se při startu zachránit soukromé klíče z poškozeného souboru s klíči + Block creation options: Možnosti vytváření bloku: + + Cannot resolve -%s address: '%s' + Nemohu přeložit -%s adresu: '%s' + Connect only to the specified node(s) Připojit se pouze k zadanému uzlu (příp. zadaným uzlům) @@ -1775,6 +3035,10 @@ Connection options: Možnosti připojení: + + Copyright (C) %i-%i + Copyright (C) %i–%i + Corrupted block database detected Bylo zjištěno poškození databáze bloků @@ -1791,6 +3055,10 @@ Do you want to rebuild the block database now? Chceš přestavět databázi bloků hned teď? + + Enable transaction replacement in the memory pool (default: %u) + Povolit výměnu transakcí v transakčním zásobníku (výchozí: %u) + Error initializing block database Chyba při zakládání databáze bloků @@ -1799,6 +3067,18 @@ Error initializing wallet database environment %s! Chyba při vytváření databázového prostředí %s pro peněženku! + + Error loading %s + Chyba při načítání %s + + + Error loading %s: Wallet corrupted + Chyba při načítání %s: peněženka je poškozená + + + Error loading %s: Wallet requires newer version of %s + Chyba při načítání %s: peněženka vyžaduje novější verzi %s + Error loading block database Chyba při načítání databáze bloků @@ -1823,10 +3103,18 @@ Incorrect or no genesis block found. Wrong datadir for network? Nemám žádný nebo jen špatný genesis blok. Není špatně nastavený datadir? + + Initialization sanity check failed. %s is shutting down. + Selhala úvodní zevrubná prověrka. %s se ukončuje. + Invalid -onion address: '%s' Neplatná -onion adresa: '%s' + + Invalid amount for -%s=<amount>: '%s' + Neplatná částka pro -%s=<částka>: '%s' + Invalid amount for -fallbackfee=<amount>: '%s' Neplatná částka pro -fallbackfee=<částka>: '%s' @@ -1835,6 +3123,10 @@ Keep the transaction memory pool below <n> megabytes (default: %u) Udržovat zasobník transakcí menší než <n> megabajtů (výchozí: %u) + + Loading banlist... + Načítám seznam klateb... + Location of the auth cookie (default: data dir) Místo pro autentizační cookie (výchozí: adresář pro data) @@ -1847,6 +3139,10 @@ Only connect to nodes in network <net> (ipv4, ipv6 or onion) Připojovat se pouze k uzlům v <net> síti (ipv4, ipv6 nebo onion) + + Print this help message and exit + Vypsat tuto nápovědu a skončit + Print version and exit Vypsat verzi a skončit @@ -1859,6 +3155,10 @@ Prune mode is incompatible with -txindex. Prořezávací režim není kompatibilní s -txindex. + + Rebuild chain state and block index from the blk*.dat files on disk + Při startu znovu vytvořit index řetězce bloků z aktuálních blk*.dat souborů + Set database cache size in megabytes (%d to %d, default: %d) Nastavit velikost databázové vyrovnávací paměti v megabajtech (%d až %d, výchozí: %d) @@ -1871,6 +3171,10 @@ Specify wallet file (within data directory) Udej název souboru s peněženkou (v rámci datového adresáře) + + Unable to bind to %s on this computer. %s is probably already running. + Nedaří se mi připojit na %s na tomhle počítači. %s už pravděpodobně jednou běží. + Unsupported argument -benchmark ignored, use -debug=bench. Nepodporovaný argument -benchmark se ignoruje, použij -debug=bench. @@ -1903,6 +3207,14 @@ Wallet %s resides outside data directory %s Peněženka %s se nachází mimo datový adresář %s + + Wallet debugging/testing options: + Možnosti ladění/testování peněženky: + + + Wallet needed to be rewritten: restart %s to complete + Soubor s peněženkou potřeboval přepsat: restartuj %s, aby se operace dokončila + Wallet options: Možnosti peněženky: @@ -1939,6 +3251,10 @@ Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) Poplatky (v %s/kB) menší než tato hodnota jsou považovány za nulové pro účely přeposílání, těžení a vytváření transakcí (výchozí: %s) + + Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d) + Vynutit přeposílání transakcí od vždy vítaných protějšků (tj. těch na bílé listině), i když porušují místní zásady pro přeposílání (výchozí: %d) + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Pokud paytxfee není nastaveno, platit dostatečný poplatek na to, aby začaly být transakce potvrzovány v průměru během n bloků (výchozí: %u) @@ -2107,6 +3423,10 @@ Warning Upozornění + + Warning: unknown new rules activated (versionbit %i) + Upozornění: aktivována neznámá nová pravidla (verzový bit %i) + Whether to operate in a blocks only mode (default: %u) Zda fungovat v čistě blokovém režimu (výchozí: %u) @@ -2199,6 +3519,10 @@ Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. This option can be specified multiple times Uživatelské jméno a zahašované heslo pro JSON-RPC spojení. Pole <userpw> má formát: <UŽIVATELSKÉ_JMÉNO>:<SŮL>$<HAŠ>. Pomocný pythonní skript je přiložen v share/rpcuser. Tuto volbu lze použít i vícekrát + + 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. + 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. + (default: %s) (výchozí: %s) diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts index 0e99b8df0..939dfe6c0 100644 --- a/src/qt/locale/bitcoin_de.ts +++ b/src/qt/locale/bitcoin_de.ts @@ -183,7 +183,43 @@ %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. %1 wird jetzt beendet, um den Verschlüsselungsprozess abzuschließen. Bitte beachten Sie, dass die Wallet-Verschlüsselung nicht vollständig vor Diebstahl Ihrer Bitcoins durch Schadprogramme schützt, die Ihren Computer befällt. - + + 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. + WICHTIG: Alle vorherigen Wallet-Sicherungen sollten durch die neu erzeugte, verschlüsselte Wallet ersetzt werden. Aus Sicherheitsgründen werden vorherige Sicherungen der unverschlüsselten Wallet nutzlos, sobald Sie die neue, verschlüsselte Wallet verwenden. + + + Wallet encryption failed + Wallet-Verschlüsselung fehlgeschlagen + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Die Wallet-Verschlüsselung ist aufgrund eines internen Fehlers fehlgeschlagen. Ihre Wallet wurde nicht verschlüsselt. + + + The supplied passphrases do not match. + Die eingegebenen Passphrasen stimmen nicht überein. + + + Wallet unlock failed + Wallet-Entsperrung fehlgeschlagen + + + The passphrase entered for the wallet decryption was incorrect. + Die eingegebene Passphrase zur Wallet-Entschlüsselung war nicht korrekt. + + + Wallet decryption failed + Wallet-Entschlüsselung fehlgeschlagen + + + Wallet passphrase was successfully changed. + Die Wallet-Passphrase wurde erfolgreich geändert. + + + Warning: The Caps Lock key is on! + Warnung: Die Feststelltaste ist aktiviert! + + BanTableModel @@ -602,6 +638,18 @@ Copy transaction ID Transaktionskennung kopieren + + Lock unspent + Nicht ausgegebenen Betrag sperren + + + Unlock unspent + Nicht ausgegebenen Betrag entsperren + + + Copy quantity + Anzahl kopieren + Copy fee Gebühr kopieren @@ -618,6 +666,10 @@ Copy priority Priorität kopieren + + Copy dust + "Staub" kopieren + Copy change Wechselgeld kopieren @@ -674,10 +726,42 @@ no nein + + This label turns red if the transaction size is greater than 1000 bytes. + Diese Bezeichnung wird rot, wenn die Transaktion größer als 1000 Byte ist. + + + This means a fee of at least %1 per kB is required. + Das bedeutet, dass eine Gebühr von mindestens %1 pro kB erforderlich ist. + + + Can vary +/- 1 byte per input. + Kann um +/- 1 Byte pro Eingabe variieren. + + + Transactions with higher priority are more likely to get included into a block. + Transaktionen mit höherer Priorität haben eine größere Chance in einen Block aufgenommen zu werden. + + + This label turns red if the priority is smaller than "medium". + Diese Bezeichnung wird rot, wenn die Priorität niedriger als "mittel" ist. + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Diese Bezeichnung wird rot, wenn irgendein Empfänger einen Betrag kleiner als die derzeitige "Staubgrenze" erhält. + + + Can vary +/- %1 satoshi(s) per input. + Kann pro Eingabe um +/- %1 Satoshi(s) abweichen. + (no label) (keine Bezeichnung) + + change from %1 (%2) + Wechselgeld von %1 (%2) + (change) (Wechselgeld) @@ -705,7 +789,39 @@ &Address &Adresse - + + New receiving address + Neue Empfangsadresse + + + New sending address + Neue Zahlungsadresse + + + Edit receiving address + Empfangsadresse bearbeiten + + + Edit sending address + Zahlungsadresse bearbeiten + + + The entered address "%1" is not a valid Bitcoin address. + Die eingegebene Adresse "%1" ist keine gültige Bitcoin-Adresse. + + + The entered address "%1" is already in the address book. + Die eingegebene Adresse "%1" befindet sich bereits im Adressbuch. + + + Could not unlock wallet. + Wallet konnte nicht entsperrt werden. + + + New key generation failed. + Erzeugung eines neuen Schlüssels fehlgeschlagen. + + FreespaceChecker @@ -845,7 +961,11 @@ Select payment request file Zahlungsanforderungsdatei auswählen - + + Select payment request file to open + Zu öffnende Zahlungsanforderungsdatei auswählen + + OptionsDialog @@ -1158,7 +1278,95 @@ PaymentServer - + + Payment request error + fehlerhafte Zahlungsanforderung + + + Cannot start bitcoin: click-to-pay handler + "bitcoin: Klicken-zum-Bezahlen"-Handler konnte nicht gestartet werden + + + URI handling + URI-Verarbeitung + + + Payment request fetch URL is invalid: %1 + Abruf-URL der Zahlungsanforderung ist ungültig: %1 + + + Invalid payment address %1 + Ungültige Zahlungsadresse %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + URI kann nicht analysiert werden! Dies kann durch eine ungültige Bitcoin-Adresse oder fehlerhafte URI-Parameter verursacht werden. + + + Payment request file handling + Zahlungsanforderungsdatei-Verarbeitung + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + Zahlungsanforderungsdatei kann nicht gelesen werden! Dies kann durch eine ungültige Zahlungsanforderungsdatei verursacht werden. + + + Payment request rejected + Zahlungsanforderung abgelehnt + + + Payment request network doesn't match client network. + Netzwerk der Zahlungsanforderung stimmt nicht mit dem Client-Netzwerk überein. + + + Payment request expired. + Zahlungsanforderung abgelaufen. + + + Payment request is not initialized. + Zahlungsanforderung ist nicht initialisiert. + + + Unverified payment requests to custom payment scripts are unsupported. + Unverifizierte Zahlungsanforderungen an benutzerdefinierte Zahlungsskripte werden nicht unterstützt. + + + Invalid payment request. + Ungültige Zahlungsanforderung. + + + Requested payment amount of %1 is too small (considered dust). + Angeforderter Zahlungsbetrag in Höhe von %1 ist zu niedrig und wurde als "Staub" eingestuft. + + + Refund from %1 + Rücküberweisung von %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Zahlungsanforderung %1 ist zu groß (%2 Byte, erlaubt sind %3 Byte). + + + Error communicating with %1: %2 + Kommunikationsfehler mit %1: %2 + + + Payment request cannot be parsed! + Zahlungsanforderung kann nicht verarbeitet werden! + + + Bad response from server %1 + Fehlerhafte Antwort vom Server: %1 + + + Network request error + fehlerhafte Netzwerkanfrage + + + Payment acknowledged + Zahlung bestätigt + + PeerTableModel @@ -1215,7 +1423,23 @@ QRImageWidget - + + &Save Image... + Grafik &speichern... + + + &Copy Image + Grafik &kopieren + + + Save QR Code + QR-Code speichern + + + PNG Image (*.png) + PNG-Grafik (*.png) + + RPCConsole @@ -1581,6 +1805,10 @@ Copy label Bezeichnung kopieren + + Copy message + Nachricht kopieren + Copy amount Betrag kopieren @@ -1604,26 +1832,74 @@ &Save Image... Grafik &speichern... + + Request payment to %1 + Zahlung anfordern an %1 + + + Payment information + Zahlungsinformationen + + + URI + URI + Address Adresse + + Amount + Betrag + Label Bezeichnung - + + Message + Nachricht + + + Resulting URI too long, try to reduce the text for label / message. + Resultierende URI ist zu lang, bitte den Text für Bezeichnung/Nachricht kürzen. + + + Error encoding URI into QR Code. + Beim Enkodieren der URI in den QR-Code ist ein Fehler aufgetreten. + + RecentRequestsTableModel + + Date + Datum + Label Bezeichnung + + Message + Nachricht + (no label) (keine Bezeichnung) - + + (no message) + (keine Nachricht) + + + (no amount requested) + (kein Betrag angefordert) + + + Requested + Angefordert + + SendCoinsDialog @@ -1774,6 +2050,10 @@ S&end &Überweisen + + Copy quantity + Anzahl kopieren + Copy amount Betrag kopieren @@ -1794,10 +2074,86 @@ Copy priority Priorität kopieren + + Copy dust + "Staub" kopieren + Copy change Wechselgeld kopieren + + %1 to %2 + %1 an %2 + + + Are you sure you want to send? + Wollen Sie die Überweisung ausführen? + + + added as transaction fee + als Transaktionsgebühr hinzugefügt + + + Total Amount %1 + Gesamtbetrag %1 + + + or + oder + + + Confirm send coins + Überweisung bestätigen + + + The recipient address is not valid. Please recheck. + Die Zahlungsadresse ist ungültig, bitte nochmals überprüfen. + + + The amount to pay must be larger than 0. + Der zu zahlende Betrag muss größer als 0 sein. + + + The amount exceeds your balance. + Der angegebene Betrag übersteigt Ihren Kontostand. + + + The total exceeds your balance when the %1 transaction fee is included. + Der angegebene Betrag übersteigt aufgrund der Transaktionsgebühr in Höhe von %1 Ihren Kontostand. + + + Duplicate address found: addresses should only be used once each. + Doppelte Adresse entdeckt: Adressen dürfen jeweils nur einmal vorkommen. + + + Transaction creation failed! + Transaktionserstellung fehlgeschlagen! + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + Die Transaktion wurde abgelehnt! Dies kann passieren, wenn einige Bitcoins aus Ihrer Wallet bereits ausgegeben wurden. Beispielsweise weil Sie eine Kopie Ihrer wallet.dat genutzt, die Bitcoins dort ausgegeben haben und dies daher in der derzeit aktiven Wallet nicht vermerkt ist. + + + A fee higher than %1 is considered an absurdly high fee. + Eine höhere Gebühr als %1 wird als unsinnig hohe Gebühr angesehen. + + + Payment request expired. + Zahlungsanforderung abgelaufen. + + + Pay only the required fee of %1 + Nur die notwendige Gebühr in Höhe von %1 zahlen + + + Estimated to begin confirmation within %n block(s). + Voraussichtlicher Beginn der Bestätigung innerhalb von %n Blöcken.Voraussichtlicher Beginn der Bestätigung innerhalb von %n Blöcken. + + + Warning: Invalid Bitcoin address + Warnung: Ungültige Bitcoin-Adresse + (no label) (keine Bezeichnung) @@ -1999,6 +2355,18 @@ TransactionDesc + + Date + Datum + + + Message + Nachricht + + + Amount + Betrag + TransactionDescDialog @@ -2009,6 +2377,10 @@ TransactionTableModel + + Date + Datum + Label Bezeichnung @@ -2040,6 +2412,10 @@ Comma separated file (*.csv) Kommagetrennte-Datei (*.csv) + + Date + Datum + Label Bezeichnung diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 7631a666c..69fe10232 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -304,12 +304,12 @@ Sign &message... - + Synchronizing with network... Synchronizing with network... - + &Overview &Overview @@ -404,12 +404,12 @@ - + Reindexing blocks on disk... Reindexing blocks on disk... - + Send coins to a Bitcoin address Send coins to a Bitcoin address @@ -439,12 +439,12 @@ &Verify message... - + Bitcoin Bitcoin - + Wallet Wallet @@ -529,7 +529,7 @@ - + %n active connection(s) to Bitcoin network %n active connection to Bitcoin network @@ -633,12 +633,12 @@ Up to date - + Show the %1 help message to get a list with possible Bitcoin command-line options - + %1 client @@ -796,7 +796,7 @@ - + Copy address @@ -862,7 +862,7 @@ - + highest @@ -1540,7 +1540,7 @@ Form - + 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. 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. @@ -1783,7 +1783,7 @@ - + %1 d @@ -1975,8 +1975,8 @@ - - + + Select a peer to view detailed information. @@ -2107,7 +2107,7 @@ - + In: @@ -2127,7 +2127,7 @@ Clear console - + &Disconnect Node @@ -2165,7 +2165,7 @@ - + Welcome to the %1 RPC console. @@ -2180,7 +2180,7 @@ Type <b>help</b> for an overview of available commands. - + %1 B @@ -2333,7 +2333,7 @@ - + Copy label @@ -3779,7 +3779,7 @@ bitcoin-core - + Options: Options: @@ -3789,22 +3789,22 @@ Specify data directory - + Connect to a node to retrieve peer addresses, and disconnect Connect to a node to retrieve peer addresses, and disconnect - + Specify your own public address Specify your own public address - + Accept command line and JSON-RPC commands Accept command line and JSON-RPC commands - + If <category> is not supplied or if <category> = 1, output all debugging information. @@ -3829,7 +3829,7 @@ - + Error: A fatal internal error occurred, see debug.log for details @@ -3839,7 +3839,7 @@ - + Pruning blockstore... @@ -3854,12 +3854,12 @@ - + Accept connections from outside (default: 1 if no -proxy or -connect) Accept connections from outside (default: 1 if no -proxy or -connect) - + Bitcoin Core Bitcoin Core @@ -3949,7 +3949,7 @@ - + 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 @@ -3979,12 +3979,7 @@ Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. - - Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. - - - - + You need to rebuild the database using -reindex-chainstate to change -txindex @@ -4173,6 +4168,11 @@ Keep the transaction memory pool below <n> megabytes (default: %u) + + + Keypool ran out, please call keypoolrefill first + + Loading banlist... @@ -4319,7 +4319,7 @@ - + Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times @@ -4394,7 +4394,12 @@ - + + Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d) + + + + The transaction amount is too small to send after the fee has been deducted @@ -4409,7 +4414,12 @@ - + + Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times. + + + + Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway @@ -4469,7 +4479,7 @@ - + Need to specify a port with -whitebind: '%s' @@ -4604,22 +4614,22 @@ Password for JSON-RPC connections - + Execute command when the best block changes (%s in cmd is replaced by block hash) Execute command when the best block changes (%s in cmd is replaced by block hash) - + Allow DNS lookups for -addnode, -seednode and -connect Allow DNS lookups for -addnode, -seednode and -connect - + Loading addresses... Loading addresses... - + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) @@ -4664,7 +4674,7 @@ - + Support filtering of blocks and transaction with bloom filters (default: %u) @@ -4734,7 +4744,7 @@ Invalid -proxy address: '%s' - + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) @@ -4819,27 +4829,27 @@ Unknown network specified in -onlynet: '%s' - + Insufficient funds Insufficient funds - + Loading block index... Loading block index... - + Add a node to connect to and attempt to keep the connection open Add a node to connect to and attempt to keep the connection open - + Loading wallet... Loading wallet... - + Cannot downgrade wallet Cannot downgrade wallet @@ -4849,12 +4859,12 @@ Cannot write default address - + Rescanning... Rescanning... - + Done loading Done loading diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts index f308f6d4d..4dbd5ee9c 100644 --- a/src/qt/locale/bitcoin_en_GB.ts +++ b/src/qt/locale/bitcoin_en_GB.ts @@ -41,10 +41,66 @@ &Delete &Delete + + Choose the address to send coins to + Choose the address to send coins to + + + Choose the address to receive coins with + Choose the address to receive coins with + + + C&hoose + C&hoose + + + Sending addresses + Sending addresses + + + Receiving addresses + Receiving addresses + + + &Copy Address + &Copy Address + + + Copy &Label + Copy &Label + + + &Edit + &Edit + + + Export Address List + Export Address List + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + Exporting Failed + Exporting Failed + AddressTableModel - + + Label + Label + + + Address + Address + + + (no label) + (no label) + + AskPassphraseDialog @@ -63,6 +119,10 @@ Repeat new passphrase Repeat new passphrase + + Encrypt wallet + Encrypt wallet + BanTableModel @@ -466,6 +526,10 @@ Priority Priority + + (no label) + (no label) + EditAddressDialog @@ -1380,9 +1444,25 @@ &Save Image... &Save Image... + + Address + Address + + + Label + Label + RecentRequestsTableModel + + Label + Label + + + (no label) + (no label) + SendCoinsDialog @@ -1534,7 +1614,11 @@ S&end S&end - + + (no label) + (no label) + + SendCoinsEntry @@ -1741,9 +1825,33 @@ TransactionTableModel + + Label + Label + + + (no label) + (no label) + TransactionView + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + Label + Label + + + Address + Address + + + Exporting Failed + Exporting Failed + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts index a0b188e5b..1fbbf74b7 100644 --- a/src/qt/locale/bitcoin_es.ts +++ b/src/qt/locale/bitcoin_es.ts @@ -49,6 +49,10 @@ Choose the address to receive coins with Seleccione la dirección de la que recibir monedas + + C&hoose + E&scoger + Sending addresses Enviando direcciones @@ -195,7 +199,27 @@ The supplied passphrases do not match. La frase clave introducida no coincide. - + + Wallet unlock failed + Fracasó el desbloqueo del monedero + + + The passphrase entered for the wallet decryption was incorrect. + La frase clave introducida para la encriptación del monedero es incorrecta. + + + Wallet decryption failed + Fracasó la encriptación del monedero + + + Wallet passphrase was successfully changed. + La frase clave del monedero se ha cambiado con éxito. + + + Warning: The Caps Lock key is on! + Alerta: ¡La clave de bloqueo Caps está activa! + + BanTableModel @@ -598,11 +622,151 @@ Priority Prioridad + + Copy address + Copiar ubicación + + + Copy label + Copiar etiqueta + + + Copy amount + Copiar cantidad + + + Copy transaction ID + Copiar ID de transacción + + + Lock unspent + Bloquear lo no gastado + + + Unlock unspent + Desbloquear lo no gastado + + + Copy quantity + Copiar cantidad + + + Copy fee + Copiar cuota + + + Copy after fee + Copiar después de couta + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridad + + + Copy dust + Copiar polvo + + + Copy change + Copiar cambio + + + highest + el más alto + + + higher + más alto + + + high + alto + + + medium-high + media altura + + + medium + medio + + + low-medium + medio bajo + + + low + bajo + + + lower + más bajo + + + lowest + el más bajo + + + (%1 locked) + (%1 bloqueado) + + + none + ninguno + + + yes + + + + no + no + + + This label turns red if the transaction size is greater than 1000 bytes. + Esta etiqueta se vuelve roja sí el tamaño de transacción es mayor de 1000 bytes. + + + This means a fee of at least %1 per kB is required. + Esto significa que se requiere una couta de al menos %1 por kB. + + + Can vary +/- 1 byte per input. + Puede variar +/- 1 byte por entrada. + + + Transactions with higher priority are more likely to get included into a block. + Las transacciones con mayor prioridad son más probablemente incluídas en un bloque. + + + This label turns red if the priority is smaller than "medium". + Esta etiqueta se vuelve roja si la priodidad es inferior a "medio". + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Esta etiqueta se vuelve roja si algún destinatario recibe una cantidad inferior a la actual puerta polvorienta. + + + Can vary +/- %1 satoshi(s) per input. + Puede variar +/- %1 satoshi(s) por entrada. + (no label) (sin etiqueta) - + + change from %1 (%2) + cambia desde %1 (%2) + + + (change) + (cambio) + + EditAddressDialog @@ -625,7 +789,39 @@ &Address &Dirección - + + New receiving address + Nueva dirección de recivimiento + + + New sending address + Nueva dirección de envío + + + Edit receiving address + Editar dirección de recivimiento + + + Edit sending address + Editar dirección de envío + + + The entered address "%1" is not a valid Bitcoin address. + La dirección introducida "%1" no es una dirección Bitcoin válida. + + + The entered address "%1" is already in the address book. + La dirección introducida "%1" está ya en la agenda. + + + Could not unlock wallet. + Podría no desbloquear el monedero. + + + New key generation failed. + Falló la generación de la nueva clave. + + FreespaceChecker @@ -761,7 +957,11 @@ Select payment request file Seleccionar archivo de sulicitud de pago - + + Select payment request file to open + Seleccionar el archivo de solicitud de pago para abrir + + OptionsDialog @@ -1074,7 +1274,95 @@ PaymentServer - + + Payment request error + Fallo en la solicitud de pago + + + Cannot start bitcoin: click-to-pay handler + No se puede iniciar bitcoin: encargado click-para-pagar + + + URI handling + Manejo de URI + + + Payment request fetch URL is invalid: %1 + La búsqueda de solicitud de pago URL es válida: %1 + + + Invalid payment address %1 + Dirección de pago inválida %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + URI no puede ser analizado! Esto puede ser causado por una dirección Bitcoin inválida o parametros URI mal formados. + + + Payment request file handling + Manejo del archivo de solicitud de pago + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + ¡El archivo de solicitud de pago no puede ser leído! Esto puede ser causado por un archivo de solicitud de pago inválido. + + + Payment request rejected + Solicitud de pago rechazada + + + Payment request network doesn't match client network. + La red de solicitud de pago no cimbina la red cliente. + + + Payment request expired. + Solicitud de pago caducada. + + + Payment request is not initialized. + La solicitud de pago no se ha iniciado. + + + Unverified payment requests to custom payment scripts are unsupported. + Solicitudes de pago sin verificar a scripts de pago habitual no se soportan. + + + Invalid payment request. + Solicitud de pago inválida. + + + Requested payment amount of %1 is too small (considered dust). + Cantidad de pago solicitada de %1 es demasiado pequeña (considerado polvo). + + + Refund from %1 + Reembolsar desde %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Solicitud de pago de %1 es demasiado grande (%2 bytes, permitidos %3 bytes). + + + Error communicating with %1: %2 + Fallo al comunicar con %1: %2 + + + Payment request cannot be parsed! + ¡La solicitud de pago no puede ser analizada! + + + Bad response from server %1 + Mala respuesta desde el servidor %1 + + + Network request error + Fallo de solicitud de red + + + Payment acknowledged + Pago declarado + + PeerTableModel @@ -1131,7 +1419,23 @@ QRImageWidget - + + &Save Image... + &Guardar imagen... + + + &Copy Image + &Copiar imagen + + + Save QR Code + Guardar código QR + + + PNG Image (*.png) + Imagen PNG (*.png) + + RPCConsole @@ -1493,7 +1797,19 @@ Remove Eliminar - + + Copy label + Copiar capa + + + Copy message + Copiar imagen + + + Copy amount + Copiar cantidad + + ReceiveRequestDialog @@ -1512,26 +1828,74 @@ &Save Image... Guardar Imagen... + + Request payment to %1 + Solicitar pago a %1 + + + Payment information + Información de pago + + + URI + URI + Address Dirección + + Amount + Cantidad + Label Etiqueta - + + Message + Mensaje + + + Resulting URI too long, try to reduce the text for label / message. + URI resultante demasiado grande, trate de reducir el texto de etiqueta / mensaje. + + + Error encoding URI into QR Code. + Fallo al codificar URI en código QR. + + RecentRequestsTableModel + + Date + Fecha + Label Etiqueta + + Message + Mensaje + (no label) (sin etiqueta) - + + (no message) + (no hay mensaje) + + + (no amount requested) + (no hay solicitud de cantidad) + + + Requested + Solicitado + + SendCoinsDialog @@ -1682,6 +2046,114 @@ S&end &Enviar + + Copy quantity + Copiar cantidad + + + Copy amount + Copiar cantidad + + + Copy fee + Copiar cuota + + + Copy after fee + Copiar después de couta + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridad + + + Copy dust + Copiar polvo + + + Copy change + Copiar cambio + + + %1 to %2 + %1 a %2 + + + Are you sure you want to send? + ¿Seguro que quiere enviar? + + + added as transaction fee + añadido como transacción de cuota + + + Total Amount %1 + Cantidad total %1 + + + or + o + + + Confirm send coins + Confirmar enviar monedas + + + The recipient address is not valid. Please recheck. + La dirección de destinatario no es válida. Por favor revísela. + + + The amount to pay must be larger than 0. + La cantidad a pagar debe de ser mayor que 0. + + + The amount exceeds your balance. + La cantidad excede su saldo. + + + The total exceeds your balance when the %1 transaction fee is included. + El total excede su saldo cuando la cuota de transacción de %1 es incluida. + + + Duplicate address found: addresses should only be used once each. + Dirección duplicada encontrada: la dirección sólo debería ser utilizada una vez por cada uso. + + + Transaction creation failed! + ¡Falló la creación de transacción! + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + ¡La transacción fue rechazada! Esto podría pasar si algunas de las monedas de su monedero fueron ya gastadas, así como si ha utilizado una copia del wallet.dat y las monedas fueron gastadas en la copia pero no marcadas como gastadas aquí. + + + A fee higher than %1 is considered an absurdly high fee. + Una couta mayor que %1 se considera una cuota irracionalmente alta. + + + Payment request expired. + Solicitud de pago caducada. + + + Pay only the required fee of %1 + Pagar únicamente la cuota solicitada de %1 + + + Estimated to begin confirmation within %n block(s). + Se estima que sea confirmado dentro del %n bloque(s).Se estima que sea confirmado dentro del %n bloque(s). + + + Warning: Invalid Bitcoin address + Alerta: dirección Bitcoin inválida + + + Warning: Unknown change address + Alerta: dirección cambiada desconocida + (no label) (sin etiqueta) @@ -1765,12 +2237,20 @@ Memo: Memo: - + + Enter a label for this address to add it to your address book + Introduzca una etiqueta para esta dirección para añadirla a su agenda + + SendConfirmationDialog - - - ShutdownWindow + + Yes + + + + + ShutdownWindow %1 is shutting down... %1 se esta cerrando... @@ -1866,7 +2346,59 @@ Reset all verify message fields Vaciar todos los campos de la verificación de mensaje - + + Click "Sign Message" to generate signature + Click en "Fírmar mensaje" para generar una firma + + + The entered address is invalid. + La dirección introducida no es válida. + + + Please check the address and try again. + Por favor revise la dirección e inténtelo de nuevo. + + + The entered address does not refer to a key. + La dirección introducida no remite a una clave. + + + Wallet unlock was cancelled. + El desbloqueo del monedero fue cancelado. + + + Private key for the entered address is not available. + La clave privada de la dirección introducida no está disponible. + + + Message signing failed. + Falló la firma del mensaje. + + + Message signed. + Mensaje firmado. + + + The signature could not be decoded. + La firma no pudo descodificarse. + + + Please check the signature and try again. + Por favor compruebe la firma y pruebe de nuevo. + + + The signature did not match the message digest. + La firma no se combinó con el mensaje. + + + Message verification failed. + Falló la verificación del mensaje. + + + Message verified. + Mensaje verificado. + + SplashScreen @@ -1883,31 +2415,419 @@ TransactionDesc - + + Open for %n more block(s) + Abrir para %n más bloque(s)Abrir para %n más bloque(s) + + + Open until %1 + Abierto hasta %1 + + + conflicted with a transaction with %1 confirmations + Hay un conflicto con la traducción de las confirmaciones %1 + + + %1/offline + %1/sin conexión + + + 0/unconfirmed, %1 + 0/no confirmado, %1 + + + in memory pool + en el equipo de memoria + + + not in memory pool + no en el equipo de memoria + + + abandoned + abandonado + + + %1/unconfirmed + %1/no confirmado + + + %1 confirmations + confirmaciones %1 + + + Status + Estado + + + , has not been successfully broadcast yet + , no ha sido emitido con éxito aún + + + , broadcast through %n node(s) + , emisión a través de %n nodo(s), emisión a través de %n nodo(s) + + + Date + Fecha + + + Source + Fuente + + + Generated + Generado + + + From + Desde + + + unknown + desconocido + + + To + Para + + + own address + dirección propia + + + watch-only + de observación + + + label + etiqueta + + + Credit + Credito + + + matures in %n more block(s) + disponible en %n bloque(s) másdisponible en %n bloque(s) más + + + not accepted + no aceptada + + + Debit + Enviado + + + Total debit + Total enviado + + + Total credit + Total recibido + + + Transaction fee + Comisión de transacción + + + Net amount + Cantidad neta + + + Message + Mensaje + + + Comment + Comentario + + + Transaction ID + Identificador de transacción (ID) + + + Output index + Indice de salida + + + Merchant + Vendedor + + + 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. + 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. + + + Debug information + Información de depuración + + + Transaction + Transacción + + + Inputs + entradas + + + Amount + Cantidad + + + true + verdadero + + + false + falso + + TransactionDescDialog This pane shows a detailed description of the transaction Esta ventana muestra información detallada sobre la transacción - + + Details for %1 + Detalles para %1 + + TransactionTableModel + + Date + Fecha + + + Type + Tipo + Label Etiqueta + + Open for %n more block(s) + Abrir para %n bloque(s) másAbrir para %n bloque(s) más + + + Open until %1 + Abierto hasta %1 + + + Offline + Sin conexion + + + Unconfirmed + Sin confirmar + + + Abandoned + Abandonado + + + Confirming (%1 of %2 recommended confirmations) + Confirmando (%1 de %2 confirmaciones recomendadas) + + + Confirmed (%1 confirmations) + Confirmado (%1 confirmaciones) + + + Conflicted + En conflicto + + + Immature (%1 confirmations, will be available after %2) + No disponible (%1 confirmaciones. Estarán disponibles al cabo de %2) + + + This block was not received by any other nodes and will probably not be accepted! + Este bloque no ha sido recibido por otros nodos y probablemente no sea aceptado! + + + Generated but not accepted + Generado pero no aceptado + + + Received with + Recibido con + + + Received from + Recibidos de + + + Sent to + Enviado a + + + Payment to yourself + Pago proprio + + + Mined + Minado + + + watch-only + de observación + + + (n/a) + (nd) + (no label) (sin etiqueta) - + + Transaction status. Hover over this field to show number of confirmations. + Estado de transacción. Pasa el ratón sobre este campo para ver el número de confirmaciones. + + + Date and time that the transaction was received. + Fecha y hora en que se recibió la transacción. + + + Type of transaction. + Tipo de transacción. + + + Whether or not a watch-only address is involved in this transaction. + Si una dirección watch-only está involucrada en esta transacción o no. + + + User-defined intent/purpose of the transaction. + Descripción de la transacción definido por el usuario. + + + Amount removed from or added to balance. + Cantidad retirada o añadida al saldo. + + TransactionView + + All + Todo + + + Today + Hoy + + + This week + Esta semana + + + This month + Este mes + + + Last month + Mes pasado + + + This year + Este año + + + Range... + Rango... + + + Received with + Recibido con + + + Sent to + Enviado a + + + To yourself + A usted mismo + + + Mined + Minado + + + Other + Otra + + + Enter address or label to search + Introduzca una dirección o etiqueta que buscar + + + Min amount + Cantidad mínima + + + Abandon transaction + Transacción abandonada + + + Copy address + Copiar ubicación + + + Copy label + Copiar capa + + + Copy amount + Copiar cantidad + + + Copy transaction ID + Copiar ID de transacción + + + Copy raw transaction + Copiar transacción raw + + + Copy full transaction details + Copiar todos los detalles de la transacción + + + Edit label + Editar etiqueta + + + Show transaction details + Mostrar detalles de la transacción + + + Export Transaction History + Exportar historial de transacciones + Comma separated file (*.csv) Archivo separado de coma (*.csv) + + Confirmed + Confirmado + + + Watch-only + De observación + + + Date + Fecha + + + Type + Tipo + Label Etiqueta @@ -1916,11 +2836,35 @@ Address Dirección + + ID + ID + Exporting Failed Falló la exportación - + + There was an error trying to save the transaction history to %1. + Ha habido un error al intentar guardar la transacción con %1. + + + Exporting Successful + Exportación finalizada + + + The transaction history was successfully saved to %1. + La transacción ha sido guardada en %1. + + + Range: + Rango: + + + to + para + + UnitDisplayStatusBarControl @@ -1930,13 +2874,53 @@ WalletFrame - + + No wallet has been loaded. + No se ha cargado ningún monedero + + WalletModel - + + Send Coins + Enviar + + WalletView - + + &Export + &Exportar + + + Export the data in the current tab to a file + Exportar a un archivo los datos de esta pestaña + + + Backup Wallet + Copia de seguridad del monedero + + + Wallet Data (*.dat) + Datos de monedero (*.dat) + + + Backup Failed + La copia de seguridad ha fallado + + + There was an error trying to save the wallet data to %1. + Ha habido un error al intentar guardar los datos del monedero en %1. + + + Backup Successful + Se ha completado con éxito la copia de respaldo + + + The wallet data was successfully saved to %1. + Los datos del monedero se han guardado con éxito en %1. + + bitcoin-core @@ -2318,6 +3302,10 @@ Specify wallet file (within data directory) Especificar archivo de monedero (dentro del directorio de datos) + + Starting network threads... + Iniciando funciones de red... + The source code is available from %s. El código fuente esta disponible desde %s. @@ -2402,6 +3390,10 @@ Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) Las comisiones (en %s/kB) mas pequeñas que esto se consideran como cero comisión para la retransmisión, minería y creación de la transacción (predeterminado: %s) + + Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d) + Fuerza la retransmisión de transacciones desde nodos en la lista blanca incluso si violan la política de retransmisiones local (predeterminado: %d) + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Si el pago de comisión no está establecido, incluir la cuota suficiente para que las transacciones comiencen la confirmación en una media de n bloques ( por defecto :%u) @@ -2556,7 +3548,7 @@ Transaction too large - Transacción demasiado grande + Transacción demasiado grande, intenta dividirla en varias. Unable to bind to %s on this computer (bind returned error %s) @@ -2564,7 +3556,7 @@ Upgrade wallet to latest format on startup - Actualizar el monedero al último formato + Actualizar el monedero al último formato al inicio Username for JSON-RPC connections @@ -2610,15 +3602,15 @@ (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) - (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) + (1 = mantener los meta datos de transacción, por ejemplo: propietario e información de pago, 2 = omitir los metadatos) -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee tiene un ajuste muy elevado! Las comisiones así de grandes podrían ser pagadas en una única transaccion. + -maxtxfee tiene un ajuste muy elevado! Comisiones muy grandes podrían ser pagadas en una única transaccion. -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - -paytxfee tiene un ajuste muy elevado! Esta es la comisión de transacción que pagaras si envías una transaccion. + -paytxfee tiene un valor muy elevado! La comisión de transacción que pagaras si envías una transaccion es alta. Do not keep transactions in the mempool longer than <n> hours (default: %u) @@ -2646,7 +3638,7 @@ Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. - Error: Unsupported argumento -socks encontrados. SOCKS versión ajuste ya no es posible, sólo SOCKS5 proxies son compatibles. + Error: argumento -socks encontrado. El ajuste de la versión SOCKS ya no es posible, sólo proxies SOCKS5 son compatibles. Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay. @@ -2746,7 +3738,7 @@ Spend unconfirmed change when sending transactions (default: %u) - Gastar cambio no confirmado al enviar transacciones (predeterminado: %u) + Usar cambio aún no confirmado al enviar transacciones (predeterminado: %u) Threshold for disconnecting misbehaving peers (default: %u) @@ -2774,7 +3766,7 @@ Cannot downgrade wallet - No se puede rebajar el monedero + No se puede cambiar a una versión mas antigua el monedero Cannot write default address diff --git a/src/qt/locale/bitcoin_es_ES.ts b/src/qt/locale/bitcoin_es_ES.ts index 40b6bb7df..8725cff58 100644 --- a/src/qt/locale/bitcoin_es_ES.ts +++ b/src/qt/locale/bitcoin_es_ES.ts @@ -3,11 +3,11 @@ AddressBookPage Right-click to edit address or label - Haz clic derecho para editar la dirección o la etiqueta + Haz clic derecho para editar la dirección o etiqueta Create a new address - Crea una nueva direccióon + Crear una nueva dirección &New @@ -15,7 +15,7 @@ Copy the currently selected address to the system clipboard - Copia la direccón seleccionada al portapapeles del sistema + Copiar la dirección seleccionada al portapapeles del sistema &Copy @@ -27,11 +27,11 @@ Delete the currently selected address from the list - Elimina la dirección seleccionada de la lista + Eliminar la dirección seleccionada de la lista Export the data in the current tab to a file - Exporta los datos de la pestaña actual a un archivo + Exportar los datos en la ficha actual a un archivo &Export @@ -41,19 +41,87 @@ &Delete &Eliminar - + + Choose the address to send coins to + Seleccione la dirección a la que enviar monedas + + + Choose the address to receive coins with + Seleccione la dirección de la que recibir monedas + + + C&hoose + E&scoger + + + Sending addresses + Enviando direcciones + + + Receiving addresses + Recibiendo direcciones + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Estas son sus direcciones Bitcoin para enviar pagos. Verifique siempre la cantidad y la dirección de recibimiento antes de enviar monedas. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Estas son sus direcciones Bitcoin para recibir pagos. Se recomienda utilizar una nueva dirección de recibimiento para cada transacción + + + &Copy Address + &Copiar Dirección + + + Copy &Label + Copiar &Etiqueta + + + &Edit + &Editar + + + Export Address List + Exportar lista de direcciones + + + Comma separated file (*.csv) + Archivo separado de coma (*.csv) + + + Exporting Failed + Falló la exportación + + + There was an error trying to save the address list to %1. Please try again. + Había un error intentando guardar la lista de direcciones en %1. Por favor inténtelo de nuevo. + + AddressTableModel - + + Label + Etiqueta + + + Address + Dirección + + + (no label) + (sin etiqueta) + + AskPassphraseDialog Passphrase Dialog - Dialogo de Contraseña + Diálogo de contraseña Enter passphrase - Introduzca la contraseña + Introducir contraseña New passphrase @@ -61,12 +129,108 @@ Repeat new passphrase - Repite la nueva contraseña + Repita la nueva contraseña + + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Introduzca la nueva frase clave del monedero. <br/>Por favor utilice una frase clave de <b>diez o más carácteres aleatorios</b>, o <b>ocho o más palabras</b>. + + + Encrypt wallet + Monedero encriptado + + + This operation needs your wallet passphrase to unlock the wallet. + Esta operación necesita su frase clave de monedero para desbloquear el monedero. + + + Unlock wallet + Desbloquear monedero + + + This operation needs your wallet passphrase to decrypt the wallet. + Esta operación necesita su frase clave de cartera para desencriptar el monedero. + + + Decrypt wallet + Desencriptar monedero + + + Change passphrase + Cambiar frase clave + + + Enter the old passphrase and new passphrase to the wallet. + Introduzca la vieja frase clave y la nueva flase clave para el monedero. + + + Confirm wallet encryption + Confirmar encriptación del monedero + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Advertencia: Si encripta su monedero y pierde su frase clave <b>PERDERÁ TODOS SUS BITCOINS</b>! + + + Are you sure you wish to encrypt your wallet? + ¿Seguro que desea encriptar su monedero? + + + Wallet encrypted + Monedero encriptado + + + %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + %1 se cerrará ahora para terminar el proceso de encriptación. Recuerde que encriptar su monedero no puede proteger completamente su monedero de ser robado por malware que infecte su ordenador. + + + 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. + IMPORTANTE: Cualquier copia de seguridad anterior que haya hecho en su archivo de monedero debería ser reemplazada con el archivo de monedero encriptado generado recientemente. Por razones de seguridad, las copias de seguridad anteriores del archivo de monedero desencriptado serán inútiles en cuanto empiece a utilizar el nuevo monedero encriptado. - + + Wallet encryption failed + Fracasó la encriptación de monedero + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Falló la encriptación del monedero debido a un error interno. Su monedero no fue encriptado. + + + The supplied passphrases do not match. + La frase clave introducida no coincide. + + + Wallet unlock failed + Fracasó el desbloqueo del monedero + + + The passphrase entered for the wallet decryption was incorrect. + La frase clave introducida para la encriptación del monedero es incorrecta. + + + Wallet decryption failed + Fracasó la encriptación del monedero + + + Wallet passphrase was successfully changed. + La frase clave del monedero se ha cambiado con éxito. + + + Warning: The Caps Lock key is on! + Alerta: ¡La clave de bloqueo Caps está activa! + + BanTableModel - + + IP/Netmask + IP/Máscara + + + Banned Until + Bloqueado Hasta + + BitcoinGUI @@ -75,7 +239,7 @@ Synchronizing with network... - Sincronizando con la red... + Sincronizando con la red… &Overview @@ -87,7 +251,7 @@ Show general overview of wallet - Mostrar vista general de la cartera + Mostrar vista general del monedero &Transactions @@ -95,7 +259,7 @@ Browse transaction history - Navegar historial de transacciones + Examinar el historial de transacciones E&xit @@ -105,37 +269,49 @@ Quit application Salir de la aplicación + + &About %1 + &Acerca de %1 + + + Show information about %1 + Mostrar información acerca de %1 + About &Qt Acerca de &Qt Show information about Qt - Muestra información acerca de Qt + Mostrar información acerca de Qt &Options... &Opciones... + + Modify configuration options for %1 + Modificar las opciones de configuración para %1 + &Encrypt Wallet... - &Encriptar Cartera... + &Cifrar monedero… &Backup Wallet... - &Hacer copia de seguridad de la cartera... + &Guardar copia del monedero... &Change Passphrase... - &Cambiar contraseña... + &Cambiar la contraseña… &Sending addresses... - &Enviando direcciones... + Direcciones de &envío... &Receiving addresses... - &Recibiendo direcciones.. + Direcciones de &recepción... Open &URI... @@ -143,123 +319,3470 @@ Reindexing blocks on disk... - Reindexando bloques en el disco... + Reindexando bloques en disco... Send coins to a Bitcoin address - Envia monedas a una dirección Bitcoin + Enviar bitcoins a una dirección Bitcoin Backup wallet to another location - Crea una copia de seguridad de tu cartera en otra ubicación + Copia de seguridad del monedero en otra ubicación + + + Change the passphrase used for wallet encryption + Cambiar la contraseña utilizada para el cifrado del monedero + + + &Debug window + &Ventana de depuración + + + Open debugging and diagnostic console + Abrir la consola de depuración y diagnóstico + + + &Verify message... + &Verificar mensaje... + + + Bitcoin + Bitcoin + + + Wallet + Monedero + + + &Send + &Enviar + + + &Receive + &Recibir + + + &Show / Hide + &Mostrar / Ocultar + + + Show or hide the main Window + Mostrar u ocultar la ventana principal + + + Encrypt the private keys that belong to your wallet + Cifrar las claves privadas de su monedero + + + Sign messages with your Bitcoin addresses to prove you own them + Firmar mensajes con sus direcciones Bitcoin para demostrar la propiedad + + + Verify messages to ensure they were signed with specified Bitcoin addresses + Verificar mensajes comprobando que están firmados con direcciones Bitcoin concretas + + + &File + &Archivo + + + &Settings + &Configuración + + + &Help + &Ayuda + + + Tabs toolbar + Barra de pestañas + + + Request payments (generates QR codes and bitcoin: URIs) + Solicitar pagos (generando códigos QR e identificadores URI "bitcoin:") + + + Show the list of used sending addresses and labels + Mostrar la lista de direcciones de envío y etiquetas - + + Show the list of used receiving addresses and labels + Muestra la lista de direcciones de recepción y etiquetas + + + Open a bitcoin: URI or payment request + Abrir un identificador URI "bitcoin:" o una petición de pago + + + &Command-line options + &Opciones de consola de comandos + + + %n active connection(s) to Bitcoin network + %n conexión activa hacia la red Bitcoin%n conexiones activas hacia la red Bitcoin + + + Indexing blocks on disk... + Indexando bloques en disco... + + + Processing blocks on disk... + Procesando bloques en disco... + + + No block source available... + Ninguna fuente de bloques disponible ... + + + Processed %n block(s) of transaction history. + %n bloque procesado del historial de transacciones.%n bloques procesados del historial de transacciones. + + + %n hour(s) + %n hora%n horas + + + %n day(s) + %n día%n días + + + %n week(s) + %n semana%n semanas + + + %1 and %2 + %1 y %2 + + + %n year(s) + %n año%n años + + + %1 behind + %1 atrás + + + Last received block was generated %1 ago. + El último bloque recibido fue generado hace %1. + + + Transactions after this will not yet be visible. + Las transacciones posteriores aún no están visibles. + + + Error + Error + + + Warning + Aviso + + + Information + Información + + + Up to date + Actualizado + + + Show the %1 help message to get a list with possible Bitcoin command-line options + Mostrar el mensaje de ayuda %1 para obtener una lista de los posibles comandos de linea de comandos de Bitcoin + + + %1 client + %1 cliente + + + Catching up... + Actualizando... + + + Date: %1 + + Fecha: %1 + + + + Amount: %1 + + Amount: %1 + + + + Type: %1 + + Tipo: %1 + + + + Label: %1 + + Etiqueta: %1 + + + + Address: %1 + + Dirección: %1 + + + + Sent transaction + Transacción enviada + + + Incoming transaction + Transacción entrante + + + Wallet is <b>encrypted</b> and currently <b>unlocked</b> + El monedero está <b>cifrado</b> y actualmente <b>desbloqueado</b> + + + Wallet is <b>encrypted</b> and currently <b>locked</b> + El monedero está <b>cifrado</b> y actualmente <b>bloqueado</b> + + CoinControlDialog - - - EditAddressDialog - &Label - Etiqueta + Coin Selection + Selección de la moneda - &Address - Dirección + Quantity: + Cantidad: - - - FreespaceChecker - - - HelpMessageDialog - - - Intro - - - OpenURIDialog - - - OptionsDialog - - - OverviewPage - - - PaymentServer - - - PeerTableModel - - - QObject - - - QRImageWidget - - - RPCConsole - - - ReceiveCoinsDialog - - - ReceiveRequestDialog - Copy &Address - &Copiar Direccón + Bytes: + Bytes: - - - RecentRequestsTableModel - - - SendCoinsDialog - - - SendCoinsEntry - - - SendConfirmationDialog - - - ShutdownWindow - - - SignVerifyMessageDialog - - - SplashScreen - - - TrafficGraphWidget - - - TransactionDesc - - - TransactionDescDialog - - - TransactionTableModel - - - TransactionView - - - UnitDisplayStatusBarControl - - - WalletFrame - - - WalletModel - - - WalletView - - - bitcoin-core - + + Amount: + Cuantía: + + + Priority: + Prioridad: + + + Fee: + Tasa: + + + Dust: + Polvo: + + + After Fee: + Después de aplicar la comisión: + + + Change: + Cambio: + + + (un)select all + (des)marcar todos + + + Tree mode + Modo árbol + + + List mode + Modo lista + + + Amount + Cantidad + + + Received with label + Recibido con etiqueta + + + Received with address + Recibido con dirección + + + Date + Fecha + + + Confirmations + Confirmaciones + + + Confirmed + Confirmado + + + Priority + Prioridad + + + Copy address + Copiar ubicación + + + Copy label + Copiar etiqueta + + + Copy amount + Copiar cantidad + + + Copy transaction ID + Copiar ID de transacción + + + Lock unspent + Bloquear lo no gastado + + + Unlock unspent + Desbloquear lo no gastado + + + Copy quantity + Copiar cantidad + + + Copy fee + Copiar cuota + + + Copy after fee + Copiar después de couta + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridad + + + Copy dust + Copiar polvo + + + Copy change + Copiar cambio + + + highest + el más alto + + + higher + más alto + + + high + alto + + + medium-high + media altura + + + medium + medio + + + low-medium + medio bajo + + + low + bajo + + + lower + más bajo + + + lowest + el más bajo + + + (%1 locked) + (%1 bloqueado) + + + none + ninguno + + + yes + + + + no + no + + + This label turns red if the transaction size is greater than 1000 bytes. + Esta etiqueta se vuelve roja sí el tamaño de transacción es mayor de 1000 bytes. + + + This means a fee of at least %1 per kB is required. + Esto significa que se requiere una couta de al menos %1 por kB. + + + Can vary +/- 1 byte per input. + Puede variar +/- 1 byte por entrada. + + + Transactions with higher priority are more likely to get included into a block. + Las transacciones con mayor prioridad son más probablemente incluídas en un bloque. + + + This label turns red if the priority is smaller than "medium". + Esta etiqueta se vuelve roja si la priodidad es inferior a "medio". + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Esta etiqueta se vuelve roja si algún destinatario recibe una cantidad inferior a la actual puerta polvorienta. + + + Can vary +/- %1 satoshi(s) per input. + Puede variar +/- %1 satoshi(s) por entrada. + + + (no label) + (sin etiqueta) + + + change from %1 (%2) + cambia desde %1 (%2) + + + (change) + (cambio) + + + + EditAddressDialog + + Edit Address + Editar Dirección + + + &Label + &Etiqueta + + + The label associated with this address list entry + La etiqueta asociada con esta entrada de la lista de direcciones + + + The address associated with this address list entry. This can only be modified for sending addresses. + La dirección asociada con esta entrada de la lista de direcciones. Solo puede ser modificada para direcciones de envío. + + + &Address + &Dirección + + + New receiving address + Nueva dirección de recivimiento + + + New sending address + Nueva dirección de envío + + + Edit receiving address + Editar dirección de recivimiento + + + Edit sending address + Editar dirección de envío + + + The entered address "%1" is not a valid Bitcoin address. + La dirección introducida "%1" no es una dirección Bitcoin válida. + + + The entered address "%1" is already in the address book. + La dirección introducida "%1" está ya en la agenda. + + + Could not unlock wallet. + Podría no desbloquear el monedero. + + + New key generation failed. + Falló la generación de la nueva clave. + + + + FreespaceChecker + + A new data directory will be created. + Se creará un nuevo directorio de datos. + + + name + nombre + + + Directory already exists. Add %1 if you intend to create a new directory here. + El directorio ya existe. Añada %1 si pretende crear aquí un directorio nuevo. + + + Path already exists, and is not a directory. + La ruta ya existe y no es un directorio. + + + Cannot create data directory here. + No se puede crear un directorio de datos aquí. + + + + HelpMessageDialog + + version + versión + + + (%1-bit) + (%1-bit) + + + About %1 + Acerda de %1 + + + Command-line options + Opciones de la línea de órdenes + + + Usage: + Uso: + + + command-line options + opciones de la consola de comandos + + + UI Options: + Opciones de interfaz de usuario: + + + Choose data directory on startup (default: %u) + Elegir directorio de datos al iniciar (predeterminado: %u) + + + Set language, for example "de_DE" (default: system locale) + Establecer el idioma, por ejemplo, "es_ES" (predeterminado: configuración regional del sistema) + + + Start minimized + Arrancar minimizado + + + Set SSL root certificates for payment request (default: -system-) + Establecer los certificados raíz SSL para solicitudes de pago (predeterminado: -system-) + + + Reset all settings changed in the GUI + Reiniciar todos los ajustes modificados en el GUI + + + + Intro + + Welcome + Bienvenido + + + Welcome to %1. + Bienvenido a %1 + + + As this is the first time the program is launched, you can choose where %1 will store its data. + Al ser la primera vez que se ejecuta el programa, puede elegir donde %1 almacenara sus datos + + + %1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + %1 va a descargar y almacenar una copia de la cadena de bloques de Bitcoin. Al menos %2GB de datos seran almacenados en este directorio, que ira creciendo con el tiempo. El monedero se guardara tambien en ese directorio. + + + Use the default data directory + Utilizar el directorio de datos predeterminado + + + Use a custom data directory: + Utilizar un directorio de datos personalizado: + + + Error: Specified data directory "%1" cannot be created. + Error: no ha podido crearse el directorio de datos especificado "%1". + + + Error + Error + + + %n GB of free space available + %n GB de espacio libre%n GB de espacio disponible + + + (of %n GB needed) + (de %n GB necesitados)(de %n GB requeridos) + + + + OpenURIDialog + + Open URI + Abrir URI... + + + Open payment request from URI or file + Abrir solicitud de pago a partir de un identificador URI o de un archivo + + + URI: + URI: + + + Select payment request file + Seleccionar archivo de sulicitud de pago + + + Select payment request file to open + Seleccionar el archivo de solicitud de pago para abrir + + + + OptionsDialog + + Options + Opciones + + + &Main + &Principal + + + Automatically start %1 after logging in to the system. + Iniciar automaticamente %1 al encender el sistema. + + + &Start %1 on system login + &Iniciar %1 al iniciar el sistema + + + Size of &database cache + Tamaño de cache de la &base de datos + + + MB + MB + + + Number of script &verification threads + Número de hilos de &verificación de scripts + + + Accept connections from outside + Aceptar conexiones desde el exterior + + + Allow incoming connections + Aceptar conexiones entrantes + + + IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1) + Dirección IP del proxy (p. ej. IPv4: 127.0.0.1 / IPv6: ::1) + + + Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu. + Minimizar en lugar de salir de la aplicación cuando la ventana está cerrada. Cuando se activa esta opción, la aplicación sólo se cerrará después de seleccionar Salir en el menú. + + + Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |. + Identificadores URL de terceros (por ejemplo, un explorador de bloques) que aparecen en la pestaña de transacciones como elementos del menú contextual. El %s en la URL es reemplazado por el valor hash de la transacción. Se pueden separar URL múltiples por una barra vertical |. + + + Third party transaction URLs + Identificadores URL de transacciones de terceros + + + Active command-line options that override above options: + Opciones activas de consola de comandos que tienen preferencia sobre las opciones anteriores: + + + Reset all client options to default. + Restablecer todas las opciones predeterminadas del cliente. + + + &Reset Options + &Restablecer opciones + + + &Network + &Red + + + (0 = auto, <0 = leave that many cores free) + (0 = automático, <0 = dejar libres ese número de núcleos) + + + W&allet + &Monedero + + + Expert + Experto + + + Enable coin &control features + Habilitar funcionalidad de &coin control + + + 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. + Si desactiva el gasto del cambio no confirmado, no se podrá usar el cambio de una transacción hasta que se alcance al menos una confirmación. Esto afecta también a cómo se calcula su saldo. + + + &Spend unconfirmed change + &Gastar cambio no confirmado + + + Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled. + Abrir automáticamente el puerto del cliente Bitcoin en el router. Esta opción solo funciona si el router admite UPnP y está activado. + + + Map port using &UPnP + Mapear el puerto mediante &UPnP + + + Connect to the Bitcoin network through a SOCKS5 proxy. + Conectarse a la red Bitcoin a través de un proxy SOCKS5. + + + &Connect through SOCKS5 proxy (default proxy): + &Conectarse a través de proxy SOCKS5 (proxy predeterminado): + + + Proxy &IP: + Dirección &IP del proxy: + + + &Port: + &Puerto: + + + Port of the proxy (e.g. 9050) + Puerto del servidor proxy (ej. 9050) + + + Used for reaching peers via: + Usado para alcanzar compañeros via: + + + Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type. + Muestra si el proxy SOCKS5 predeterminado es utilizado para llegar a los pares a traves de este tipo de red. + + + IPv4 + IPv4 + + + IPv6 + IPv6 + + + Tor + Tor + + + Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. + Conectar a la red Bitcoin mediante un proxy SOCKS5 por separado para los servicios ocultos de Tor. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services: + Usar distintos proxys SOCKS5 para comunicarse vía Tor de forma anónima: + + + &Window + &Ventana + + + &Hide the icon from the system tray. + &Ocultar el icono de la barra de tareas + + + Hide tray icon + Ocultar barra de tareas + + + Show only a tray icon after minimizing the window. + Minimizar la ventana a la bandeja de iconos del sistema. + + + &Minimize to the tray instead of the taskbar + &Minimizar a la bandeja en vez de a la barra de tareas + + + M&inimize on close + M&inimizar al cerrar + + + &Display + &Interfaz + + + User Interface &language: + I&dioma de la interfaz de usuario + + + The user interface language can be set here. This setting will take effect after restarting %1. + El idioma de la interfaz de usuario puede establecerse aquí. Esta configuración tendrá efecto tras reiniciar %1. + + + &Unit to show amounts in: + Mostrar las cantidades en la &unidad: + + + Choose the default subdivision unit to show in the interface and when sending coins. + Elegir la subdivisión predeterminada para mostrar cantidades en la interfaz y cuando se envían bitcoins. + + + Whether to show coin control features or not. + Mostrar o no funcionalidad de Coin Control + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + default + predeterminado + + + none + ninguna + + + Confirm options reset + Confirme el restablecimiento de las opciones + + + Client restart required to activate changes. + Se necesita reiniciar el cliente para activar los cambios. + + + Client will be shut down. Do you want to proceed? + El cliente se cerrará. ¿Desea continuar? + + + This change would require a client restart. + Este cambio exige el reinicio del cliente. + + + The supplied proxy address is invalid. + La dirección proxy indicada es inválida. + + + + OverviewPage + + Form + Formulario + + + 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. + La información mostrada puede estar desactualizada. Su monedero se sincroniza automáticamente con la red Bitcoin después de que se haya establecido una conexión, pero este proceso aún no se ha completado. + + + Watch-only: + De observación: + + + Available: + Disponible: + + + Your current spendable balance + Su saldo disponible actual + + + Pending: + Pendiente: + + + Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance + Total de transacciones pendientes de confirmar y que aún no contribuye al saldo disponible + + + Immature: + No madurado: + + + Mined balance that has not yet matured + Saldo recién minado que aún no ha madurado. + + + Balances + Saldos + + + Total: + Total: + + + Your current total balance + Su saldo actual total + + + Your current balance in watch-only addresses + Su saldo actual en direcciones watch-only + + + Spendable: + Gastable: + + + Recent transactions + Transacciones recientes + + + Unconfirmed transactions to watch-only addresses + Transacciones sin confirmar en direcciones watch-only + + + Mined balance in watch-only addresses that has not yet matured + Saldo minado en direcciones watch-only que aún no ha madurado + + + Current total balance in watch-only addresses + Saldo total en las direcciones watch-only + + + + PaymentServer + + Payment request error + Fallo en la solicitud de pago + + + Cannot start bitcoin: click-to-pay handler + No se puede iniciar bitcoin: encargado click-para-pagar + + + URI handling + Manejo de URI + + + Payment request fetch URL is invalid: %1 + La búsqueda de solicitud de pago URL es válida: %1 + + + Invalid payment address %1 + Dirección de pago inválida %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + URI no puede ser analizado! Esto puede ser causado por una dirección Bitcoin inválida o parametros URI mal formados. + + + Payment request file handling + Manejo del archivo de solicitud de pago + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + ¡El archivo de solicitud de pago no puede ser leído! Esto puede ser causado por un archivo de solicitud de pago inválido. + + + Payment request rejected + Solicitud de pago rechazada + + + Payment request network doesn't match client network. + La red de solicitud de pago no cimbina la red cliente. + + + Payment request expired. + Solicitud de pago caducada. + + + Payment request is not initialized. + La solicitud de pago no se ha iniciado. + + + Unverified payment requests to custom payment scripts are unsupported. + Solicitudes de pago sin verificar a scripts de pago habitual no se soportan. + + + Invalid payment request. + Solicitud de pago inválida. + + + Requested payment amount of %1 is too small (considered dust). + Cantidad de pago solicitada de %1 es demasiado pequeña (considerado polvo). + + + Refund from %1 + Reembolsar desde %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Solicitud de pago de %1 es demasiado grande (%2 bytes, permitidos %3 bytes). + + + Error communicating with %1: %2 + Fallo al comunicar con %1: %2 + + + Payment request cannot be parsed! + ¡La solicitud de pago no puede ser analizada! + + + Bad response from server %1 + Mala respuesta desde el servidor %1 + + + Network request error + Fallo de solicitud de red + + + Payment acknowledged + Pago declarado + + + + PeerTableModel + + User Agent + User Agent + + + Node/Service + Nodo/Servicio + + + Ping Time + Ping + + + + QObject + + Amount + Cantidad + + + Enter a Bitcoin address (e.g. %1) + Introducir una dirección Bitcoin (p. ej. %1) + + + %1 d + %1 d + + + %1 h + %1 h + + + %1 m + %1 m + + + %1 s + %1 s + + + None + Ninguno + + + N/A + N/D + + + %1 ms + %1 ms + + + + QRImageWidget + + &Save Image... + &Guardar imagen... + + + &Copy Image + &Copiar imagen + + + Save QR Code + Guardar código QR + + + PNG Image (*.png) + Imagen PNG (*.png) + + + + RPCConsole + + N/A + N/D + + + Client version + Versión del cliente + + + &Information + &Información + + + Debug window + Ventana de depuración + + + General + General + + + Using BerkeleyDB version + Utilizando la versión de BerkeleyDB + + + Datadir + Datadir + + + Startup time + Hora de inicio + + + Network + Red + + + Name + Nombre + + + Number of connections + Número de conexiones + + + Block chain + Cadena de bloques + + + Current number of blocks + Número actual de bloques + + + Memory Pool + Piscina de Memoria + + + Current number of transactions + Número actual de transacciones + + + Memory usage + Uso de memoria + + + Received + Recibido + + + Sent + Enviado + + + &Peers + &Pares + + + Banned peers + Peers Bloqueados + + + Select a peer to view detailed information. + Seleccionar un par para ver su información detallada. + + + Whitelisted + En la lista blanca + + + Direction + Dirección + + + Version + Versión + + + Starting Block + Importando bloques... + + + Synced Headers + Sincronizar Cabeceras + + + Synced Blocks + Bloques Sincronizados + + + User Agent + User Agent + + + Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. + Abrir el archivo de depuración %1 desde el directorio de datos actual. Puede tardar unos segundos para ficheros de gran tamaño. + + + Decrease font size + Disminuir tamaño de letra + + + Increase font size + Aumentar tamaño de letra + + + Services + Servicios + + + Ban Score + Puntuación de bloqueo + + + Connection Time + Duración de la conexión + + + Last Send + Ultimo envío + + + Last Receive + Ultima recepción + + + Ping Time + Ping + + + The duration of a currently outstanding ping. + La duración de un ping actualmente en proceso. + + + Ping Wait + Espera de Ping + + + Time Offset + Desplazamiento de tiempo + + + Last block time + Hora del último bloque + + + &Open + &Abrir + + + &Console + &Consola + + + &Network Traffic + &Tráfico de Red + + + &Clear + &Vaciar + + + Totals + Total: + + + In: + Entrante: + + + Out: + Saliente: + + + Debug log file + Archivo de registro de depuración + + + Clear console + Borrar consola + + + &Disconnect Node + Nodo &Desconectado + + + Ban Node for + Prohibir Nodo para + + + 1 &hour + 1 &hora + + + 1 &day + 1 &día + + + 1 &week + 1 &semana + + + 1 &year + 1 &año + + + &Unban Node + &Desbanear Nodo + + + Welcome to the %1 RPC console. + Bienvenido a la consola RPC %1. + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Use las flechas arriba y abajo para navegar por el historial y <b>Control+L</b> para vaciar la pantalla. + + + Type <b>help</b> for an overview of available commands. + Escriba <b>help</b> para ver un resumen de los comandos disponibles. + + + %1 B + %1 B + + + %1 KB + %1 KB + + + %1 MB + %1 MB + + + %1 GB + %1 GB + + + (node id: %1) + (nodo: %1) + + + via %1 + via %1 + + + never + nunca + + + Inbound + Entrante + + + Outbound + Saliente + + + Yes + + + + No + No + + + Unknown + Desconocido + + + + ReceiveCoinsDialog + + &Amount: + Cantidad + + + &Label: + &Etiqueta: + + + &Message: + Mensaje: + + + Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before. + Reutilizar una de las direcciones previamente usadas para recibir. Reutilizar direcciones tiene problemas de seguridad y privacidad. No lo uses a menos que antes regeneres una solicitud de pago. + + + R&euse an existing receiving address (not recommended) + R&eutilizar una dirección existente para recibir (no recomendado) + + + 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. + Un mensaje opcional para adjuntar a la solicitud de pago, que se muestra cuando se abre la solicitud. Nota: El mensaje no se enviará con el pago por la red Bitcoin. + + + An optional label to associate with the new receiving address. + Etiqueta opcional para asociar con la nueva dirección de recepción. + + + Use this form to request payments. All fields are <b>optional</b>. + Utilice este formulario para solicitar pagos. Todos los campos son <b>opcionales</b>. + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + Para solicitar una cantidad opcional. Deje este vacío o cero para no solicitar una cantidad específica. + + + Clear all fields of the form. + Vaciar todos los campos del formulario. + + + Clear + Vaciar + + + Requested payments history + Historial de pagos solicitados + + + &Request payment + &Solicitar pago + + + Show the selected request (does the same as double clicking an entry) + Muestra la petición seleccionada (También doble clic) + + + Show + Mostrar + + + Remove the selected entries from the list + Borrar de la lista las direcciónes actualmente seleccionadas + + + Remove + Eliminar + + + Copy label + Copiar capa + + + Copy message + Copiar imagen + + + Copy amount + Copiar cantidad + + + + ReceiveRequestDialog + + QR Code + Código QR + + + Copy &URI + Copiar &URI + + + Copy &Address + Copiar &Dirección + + + &Save Image... + Guardar Imagen... + + + Request payment to %1 + Solicitar pago a %1 + + + Payment information + Información de pago + + + URI + URI + + + Address + Dirección + + + Amount + Cantidad + + + Label + Etiqueta + + + Message + Mensaje + + + Resulting URI too long, try to reduce the text for label / message. + URI resultante demasiado grande, trate de reducir el texto de etiqueta / mensaje. + + + Error encoding URI into QR Code. + Fallo al codificar URI en código QR. + + + + RecentRequestsTableModel + + Date + Fecha + + + Label + Etiqueta + + + Message + Mensaje + + + (no label) + (sin etiqueta) + + + (no message) + (no hay mensaje) + + + (no amount requested) + (no hay solicitud de cantidad) + + + Requested + Solicitado + + + + SendCoinsDialog + + Send Coins + Enviar bitcoins + + + Coin Control Features + Características de Coin Control + + + Inputs... + Entradas... + + + automatically selected + Seleccionado automáticamente + + + Insufficient funds! + Fondos insuficientes! + + + Quantity: + Cantidad: + + + Bytes: + Bytes: + + + Amount: + Cuantía: + + + Priority: + Prioridad: + + + Fee: + Tasa: + + + After Fee: + Después de tasas: + + + Change: + Cambio: + + + If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address. + Si se marca esta opción pero la dirección de cambio está vacía o es inválida, el cambio se enviará a una nueva dirección recién generada. + + + Custom change address + Dirección propia + + + Transaction Fee: + Comisión de Transacción: + + + Choose... + Elija... + + + collapse fee-settings + Colapsar ajustes de cuota + + + per kilobyte + por kilobyte + + + If the custom fee is set to 1000 satoshis and the transaction is only 250 bytes, then "per kilobyte" only pays 250 satoshis in fee, while "total at least" pays 1000 satoshis. For transactions bigger than a kilobyte both pay by kilobyte. + Si la tarifa de aduana se establece en 1000 satoshis y la transacción está a sólo 250 bytes, entonces "por kilobyte" sólo paga 250 satoshis de cuota, mientras que "el mínimo total" pagaría 1.000 satoshis. Para las transacciones más grandes que un kilobyte ambos pagan por kilobyte + + + Hide + Ocultar + + + total at least + total por lo menos + + + Paying only the minimum fee is just fine as long as there is less transaction volume than space in the blocks. But be aware that this can end up in a never confirming transaction once there is more demand for bitcoin transactions than the network can process. + Pagando solamente la cuota mínima es correcto, siempre y cuando haya menos volumen de transacciones que el espacio en los bloques. Pero tenga en cuenta que esto puede terminar en una transacción nunca confirmada, una vez que haya más demanda para transacciones Bitcoin que la red pueda procesar. + + + (read the tooltip) + (leer la sugerencia) + + + Recommended: + Recomendado: + + + Custom: + Personalizado: + + + (Smart fee not initialized yet. This usually takes a few blocks...) + (Tarifa inteligente no inicializado aún. Esto generalmente lleva a pocos bloques...) + + + Confirmation time: + Tiempo de confirmación: + + + normal + normal + + + fast + rápido + + + Send to multiple recipients at once + Enviar a múltiples destinatarios de una vez + + + Add &Recipient + Añadir &destinatario + + + Clear all fields of the form. + Vaciar todos los campos del formulario + + + Dust: + Polvo: + + + Clear &All + Vaciar &todo + + + Balance: + Saldo: + + + Confirm the send action + Confirmar el envío + + + S&end + &Enviar + + + Copy quantity + Copiar cantidad + + + Copy amount + Copiar cantidad + + + Copy fee + Copiar cuota + + + Copy after fee + Copiar después de couta + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridad + + + Copy dust + Copiar polvo + + + Copy change + Copiar cambio + + + %1 to %2 + %1 a %2 + + + Are you sure you want to send? + ¿Seguro que quiere enviar? + + + added as transaction fee + añadido como transacción de cuota + + + Total Amount %1 + Cantidad total %1 + + + or + o + + + Confirm send coins + Confirmar enviar monedas + + + The recipient address is not valid. Please recheck. + La dirección de destinatario no es válida. Por favor revísela. + + + The amount to pay must be larger than 0. + La cantidad a pagar debe de ser mayor que 0. + + + The amount exceeds your balance. + La cantidad excede su saldo. + + + The total exceeds your balance when the %1 transaction fee is included. + El total excede su saldo cuando la cuota de transacción de %1 es incluida. + + + Duplicate address found: addresses should only be used once each. + Dirección duplicada encontrada: la dirección sólo debería ser utilizada una vez por cada uso. + + + Transaction creation failed! + ¡Falló la creación de transacción! + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + ¡La transacción fue rechazada! Esto podría pasar si algunas de las monedas de su monedero fueron ya gastadas, así como si ha utilizado una copia del wallet.dat y las monedas fueron gastadas en la copia pero no marcadas como gastadas aquí. + + + A fee higher than %1 is considered an absurdly high fee. + Una couta mayor que %1 se considera una cuota irracionalmente alta. + + + Payment request expired. + Solicitud de pago caducada. + + + Pay only the required fee of %1 + Pagar únicamente la cuota solicitada de %1 + + + Estimated to begin confirmation within %n block(s). + Se estima que sea confirmado dentro del %n bloque(s).Se estima que sea confirmado dentro del %n bloque(s). + + + Warning: Invalid Bitcoin address + Alerta: dirección Bitcoin inválida + + + Warning: Unknown change address + Alerta: dirección cambiada desconocida + + + (no label) + (sin etiqueta) + + + + SendCoinsEntry + + A&mount: + Ca&ntidad: + + + Pay &To: + &Pagar a: + + + &Label: + &Etiqueta: + + + Choose previously used address + Escoger direcciones previamente usadas + + + This is a normal payment. + Esto es un pago ordinario. + + + The Bitcoin address to send the payment to + Dirección Bitcoin a la que enviar el pago + + + Alt+A + Alt+A + + + Paste address from clipboard + Pegar dirección desde portapapeles + + + Alt+P + Alt+P + + + Remove this entry + Eliminar esta transacción + + + 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. + La cuota será deducida de la cantidad que sea mandada. El destinatario recibirá menos bitcoins de los que entres en el + + + S&ubtract fee from amount + Restar comisiones a la cantidad + + + Message: + Mensaje: + + + This is an unauthenticated payment request. + Esta es una petición de pago no autentificada. + + + This is an authenticated payment request. + Esta es una petición de pago autentificada. + + + Enter a label for this address to add it to the list of used addresses + Introduce una etiqueta para esta dirección para añadirla a la lista de direcciones utilizadas + + + 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. + Un mensaje que se adjuntó a la bitcoin: URL que será almacenada con la transacción para su referencia. Nota: Este mensaje no se envía a través de la red Bitcoin. + + + Pay To: + Paga a: + + + Memo: + Memo: + + + Enter a label for this address to add it to your address book + Introduzca una etiqueta para esta dirección para añadirla a su agenda + + + + SendConfirmationDialog + + Yes + + + + + ShutdownWindow + + %1 is shutting down... + %1 se esta cerrando... + + + Do not shut down the computer until this window disappears. + No apague el equipo hasta que desaparezca esta ventana. + + + + SignVerifyMessageDialog + + Signatures - Sign / Verify a Message + Firmas - Firmar / verificar un mensaje + + + &Sign Message + &Firmar mensaje + + + 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. + Puede firmar los mensajes con sus direcciones para demostrar que las posee. Tenga cuidado de no firmar cualquier cosa de manera vaga o aleatoria, pues los ataques de phishing pueden tratar de engañarle firmando su identidad a través de ellos. Sólo firme declaraciones totalmente detalladas con las que usted esté de acuerdo. + + + The Bitcoin address to sign the message with + Dirección Bitcoin con la que firmar el mensaje + + + Choose previously used address + Escoger dirección previamente usada + + + Alt+A + Alt+A + + + Paste address from clipboard + Pegar dirección desde portapapeles + + + Alt+P + Alt+P + + + Enter the message you want to sign here + Introduzca el mensaje que desea firmar aquí + + + Signature + Firma + + + Copy the current signature to the system clipboard + Copiar la firma actual al portapapeles del sistema + + + Sign the message to prove you own this Bitcoin address + Firmar el mensaje para demostrar que se posee esta dirección Bitcoin + + + Sign &Message + Firmar &mensaje + + + Reset all sign message fields + Vaciar todos los campos de la firma de mensaje + + + Clear &All + Vaciar &todo + + + &Verify Message + &Verificar mensaje + + + 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! + Introduzca la dirección para la firma, el mensaje (asegurándose de copiar tal cual los saltos de línea, espacios, tabulaciones, etc.) y la firma a continuación para verificar el mensaje. Tenga cuidado de no asumir más información de lo que dice el propio mensaje firmado para evitar fraudes basados en ataques de tipo man-in-the-middle. + + + The Bitcoin address the message was signed with + La dirección Bitcoin con la que se firmó el mensaje + + + Verify the message to ensure it was signed with the specified Bitcoin address + Verificar el mensaje para comprobar que fue firmado con la dirección Bitcoin indicada + + + Verify &Message + Verificar &mensaje + + + Reset all verify message fields + Vaciar todos los campos de la verificación de mensaje + + + Click "Sign Message" to generate signature + Click en "Fírmar mensaje" para generar una firma + + + The entered address is invalid. + La dirección introducida no es válida. + + + Please check the address and try again. + Por favor revise la dirección e inténtelo de nuevo. + + + The entered address does not refer to a key. + La dirección introducida no remite a una clave. + + + Wallet unlock was cancelled. + El desbloqueo del monedero fue cancelado. + + + Private key for the entered address is not available. + La clave privada de la dirección introducida no está disponible. + + + Message signing failed. + Falló la firma del mensaje. + + + Message signed. + Mensaje firmado. + + + The signature could not be decoded. + La firma no pudo descodificarse. + + + Please check the signature and try again. + Por favor compruebe la firma y pruebe de nuevo. + + + The signature did not match the message digest. + La firma no se combinó con el mensaje. + + + Message verification failed. + Falló la verificación del mensaje. + + + Message verified. + Mensaje verificado. + + + + SplashScreen + + [testnet] + [testnet] + + + + TrafficGraphWidget + + KB/s + KB/s + + + + TransactionDesc + + Open for %n more block(s) + Abrir para %n más bloque(s)Abrir para %n más bloque(s) + + + Open until %1 + Abierto hasta %1 + + + conflicted with a transaction with %1 confirmations + Hay un conflicto con la traducción de las confirmaciones %1 + + + %1/offline + %1/sin conexión + + + 0/unconfirmed, %1 + 0/no confirmado, %1 + + + in memory pool + en el equipo de memoria + + + not in memory pool + no en el equipo de memoria + + + abandoned + abandonado + + + %1/unconfirmed + %1/no confirmado + + + %1 confirmations + confirmaciones %1 + + + Status + Estado + + + , has not been successfully broadcast yet + , no ha sido emitido con éxito aún + + + , broadcast through %n node(s) + , emisión a través de %n nodo(s), emisión a través de %n nodo(s) + + + Date + Fecha + + + Source + Fuente + + + Generated + Generado + + + From + Desde + + + unknown + desconocido + + + To + Para + + + own address + dirección propia + + + watch-only + de observación + + + label + etiqueta + + + Credit + Credito + + + matures in %n more block(s) + disponible en %n bloque(s) másdisponible en %n bloque(s) más + + + not accepted + no aceptada + + + Debit + Enviado + + + Total debit + Total enviado + + + Total credit + Total recibido + + + Transaction fee + Comisión de transacción + + + Net amount + Cantidad neta + + + Message + Mensaje + + + Comment + Comentario + + + Transaction ID + Identificador de transacción (ID) + + + Output index + Indice de salida + + + Merchant + Vendedor + + + 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. + 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. + + + Debug information + Información de depuración + + + Transaction + Transacción + + + Inputs + entradas + + + Amount + Cantidad + + + true + verdadero + + + false + falso + + + + TransactionDescDialog + + This pane shows a detailed description of the transaction + Esta ventana muestra información detallada sobre la transacción + + + Details for %1 + Detalles para %1 + + + + TransactionTableModel + + Date + Fecha + + + Type + Tipo + + + Label + Etiqueta + + + Open for %n more block(s) + Abrir para %n bloque(s) másAbrir para %n bloque(s) más + + + Open until %1 + Abierto hasta %1 + + + Offline + Sin conexion + + + Unconfirmed + Sin confirmar + + + Abandoned + Abandonado + + + Confirming (%1 of %2 recommended confirmations) + Confirmando (%1 de %2 confirmaciones recomendadas) + + + Confirmed (%1 confirmations) + Confirmado (%1 confirmaciones) + + + Conflicted + En conflicto + + + Immature (%1 confirmations, will be available after %2) + No disponible (%1 confirmaciones. Estarán disponibles al cabo de %2) + + + This block was not received by any other nodes and will probably not be accepted! + Este bloque no ha sido recibido por otros nodos y probablemente no sea aceptado! + + + Generated but not accepted + Generado pero no aceptado + + + Received with + Recibido con + + + Received from + Recibidos de + + + Sent to + Enviado a + + + Payment to yourself + Pago proprio + + + Mined + Minado + + + watch-only + de observación + + + (n/a) + (nd) + + + (no label) + (sin etiqueta) + + + Transaction status. Hover over this field to show number of confirmations. + Estado de transacción. Pasa el ratón sobre este campo para ver el número de confirmaciones. + + + Date and time that the transaction was received. + Fecha y hora en que se recibió la transacción. + + + Type of transaction. + Tipo de transacción. + + + Whether or not a watch-only address is involved in this transaction. + Si una dirección watch-only está involucrada en esta transacción o no. + + + User-defined intent/purpose of the transaction. + Descripción de la transacción definido por el usuario. + + + Amount removed from or added to balance. + Cantidad retirada o añadida al saldo. + + + + TransactionView + + All + Todo + + + Today + Hoy + + + This week + Esta semana + + + This month + Este mes + + + Last month + Mes pasado + + + This year + Este año + + + Range... + Rango... + + + Received with + Recibido con + + + Sent to + Enviado a + + + To yourself + A usted mismo + + + Mined + Minado + + + Other + Otra + + + Enter address or label to search + Introduzca una dirección o etiqueta que buscar + + + Min amount + Cantidad mínima + + + Abandon transaction + Transacción abandonada + + + Copy address + Copiar ubicación + + + Copy label + Copiar capa + + + Copy amount + Copiar cantidad + + + Copy transaction ID + Copiar ID de transacción + + + Copy raw transaction + Copiar transacción raw + + + Copy full transaction details + Copiar todos los detalles de la transacción + + + Edit label + Editar etiqueta + + + Show transaction details + Mostrar detalles de la transacción + + + Export Transaction History + Exportar historial de transacciones + + + Comma separated file (*.csv) + Archivo separado de coma (*.csv) + + + Confirmed + Confirmado + + + Watch-only + De observación + + + Date + Fecha + + + Type + Tipo + + + Label + Etiqueta + + + Address + Dirección + + + ID + ID + + + Exporting Failed + Falló la exportación + + + There was an error trying to save the transaction history to %1. + Ha habido un error al intentar guardar la transacción con %1. + + + Exporting Successful + Exportación finalizada + + + The transaction history was successfully saved to %1. + La transacción ha sido guardada en %1. + + + Range: + Rango: + + + to + para + + + + UnitDisplayStatusBarControl + + Unit to show amounts in. Click to select another unit. + Unidad en la que se muestran las cantidades. Haga clic para seleccionar otra unidad. + + + + WalletFrame + + No wallet has been loaded. + No se ha cargado ningún monedero + + + + WalletModel + + Send Coins + Enviar + + + + WalletView + + &Export + &Exportar + + + Export the data in the current tab to a file + Exportar a un archivo los datos de esta pestaña + + + Backup Wallet + Copia de seguridad del monedero + + + Wallet Data (*.dat) + Datos de monedero (*.dat) + + + Backup Failed + La copia de seguridad ha fallado + + + There was an error trying to save the wallet data to %1. + Ha habido un error al intentar guardar los datos del monedero en %1. + + + Backup Successful + Se ha completado con éxito la copia de respaldo + + + The wallet data was successfully saved to %1. + Los datos del monedero se han guardado con éxito en %1. + + + + bitcoin-core + + Options: + Opciones: + + + + Specify data directory + Especificar directorio para los datos + + + Connect to a node to retrieve peer addresses, and disconnect + Conectar a un nodo para obtener direcciones de pares y desconectar + + + Specify your own public address + Especifique su propia dirección pública + + + Accept command line and JSON-RPC commands + Aceptar comandos consola y JSON-RPC + + + + If <category> is not supplied or if <category> = 1, output all debugging information. + Si <category> no es proporcionado o si <category> =1, muestra toda la información de depuración. + + + Prune configured below the minimum of %d MiB. Please use a higher number. + La Poda se ha configurado por debajo del minimo de %d MiB. Por favor utiliza un valor mas alto. + + + Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) + Poda: la ultima sincronizacion de la cartera sobrepasa los datos podados. Necesitas reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado) + + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Reduce los requisitos de almacenaje podando (eliminando) los bloques viejos. Este modo es incompatible con -txindex y -rescan. Advertencia: Revertir este ajuste requiere volver a descargar la cadena de bloques al completo. (predeterminado: 0 = deshabilitar la poda de bloques, >%u = objetivo de tamaño en MiB para usar para los archivos de bloques) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Nos es posible re-escanear en modo podado.Necesitas utilizar -reindex el cual descargara la cadena de bloques al completo de nuevo. + + + Error: A fatal internal error occurred, see debug.log for details + Un error interno fatal ocurrió, ver debug.log para detalles + + + Fee (in %s/kB) to add to transactions you send (default: %s) + Comisión (en %s/KB) para agregar a las transacciones que envíe (por defecto: %s) + + + Pruning blockstore... + Poda blockstore ... + + + Run in the background as a daemon and accept commands + Ejecutar en segundo plano como daemon y aceptar comandos + + + + Unable to start HTTP server. See debug log for details. + No se ha podido comenzar el servidor HTTP. Ver debug log para detalles. + + + Accept connections from outside (default: 1 if no -proxy or -connect) + Aceptar conexiones desde el exterior (predeterminado: 1 si no -proxy o -connect) + + + Bitcoin Core + Bitcoin Core + + + The %s developers + Los %s desarrolladores + + + -fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available. + -fallbackfee tiene un ajuste muy alto! Esta es la comisión de transacción que pagarás cuando las estimaciones de comisiones no estén disponibles. + + + A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s) + Una comision (en %s/kB) que sera usada cuando las estimacion de comision no disponga de suficientes datos (predeterminado: %s) + + + Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d) + Aceptar transacciones retransmitidas recibidas desde nodos en la lista blanca incluso cuando no estés retransmitiendo transacciones (predeterminado: %d) + + + Bind to given address and always listen on it. Use [host]:port notation for IPv6 + Vincular a la dirección dada y escuchar siempre en ella. Utilice la notación [host]:port para IPv6 + + + Cannot obtain a lock on data directory %s. %s is probably already running. + No se puede bloquear el directorio %s. %s ya se está ejecutando. + + + Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup + Borrar todas las transacciones del monedero y sólo recuperar aquellas partes de la cadena de bloques por medio de -rescan on startup. + + + Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. + Distribuido bajo la licencia de software MIT, vea la copia del archivo adjunto o <http://www.opensource.org/licenses/mit-license.php>. + + + Equivalent bytes per sigop in transactions for relay and mining (default: %u) + Bytes equivalentes por sigop en transacciones para retrasmisión y minado (predeterminado: %u) + + + Error loading %s: You can't enable HD on a already existing non-HD wallet + Error cargando %s: No puede habilitar HD en un monedero existente que no es HD + + + Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect. + Error leyendo %s!. Todas las claves se han leido correctamente, pero los datos de transacciones o la libreta de direcciones pueden faltar o ser incorrectos. + + + Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) + Ejecutar comando cuando una transacción del monedero cambia (%s en cmd se remplazará por TxID) + + + 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) + Ajuste máximo permitido del tiempo offset medio de pares. La perspectiva local de tiempo se verá influenciada por los pares anteriores y posteriores a esta cantidad. (Por defecto: %u segundos) + + + Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s) + Máximas comisiones totales (en %s) para utilizar en una sola transacción de la cartera; establecer esto demasiado bajo puede abortar grandes transacciones (predeterminado: %s) + + + Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly. + Por favor, compruebe si la fecha y hora en su computadora son correctas! Si su reloj esta mal, %s no trabajara correctamente. + + + Please contribute if you find %s useful. Visit %s for further information about the software. + Contribuya si encuentra %s de utilidad. Visite %s para mas información acerca del programa. + + + Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d) + Establecer el número de hilos (threads) de verificación de scripts (entre %u y %d, 0 = automático, <0 = dejar libres ese número de núcleos; predeterminado: %d) + + + The block database contains a block which appears to be from the future. This may be due to your computer's date and time being set incorrectly. Only rebuild the block database if you are sure that your computer's date and time are correct + La base de datos de bloques contiene un bloque que parece ser del futuro. Esto puede ser porque la fecha y hora de tu ordenador están mal ajustados. Reconstruye la base de datos de bloques solo si estas seguro de que la fecha y hora de tu ordenador estan ajustados correctamente. + + + This is a pre-release test build - use at your own risk - do not use for mining or merchant applications + Esta es una versión de pre-prueba - utilícela bajo su propio riesgo. No la utilice para usos comerciales o de minería. + + + Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain + No es posible reconstruir la base de datos a un estado anterior. Debe descargar de nuevo la cadena de bloques. + + + Use UPnP to map the listening port (default: 1 when listening and no -proxy) + Utiliza UPnP para asignar el puerto de escucha (predeterminado: 1 cuando esta escuchando sin -proxy) + + + Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues. + Atención: ¡Parece que la red no está totalmente de acuerdo! Algunos mineros están presentando inconvenientes. + + + Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade. + Atención: ¡Parece que no estamos completamente de acuerdo con nuestros pares! Podría necesitar una actualización, u otros nodos podrían necesitarla. + + + Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times. + Poner en lista blanca a los equipos que se conecten desde la máscara de subred o dirección IP especificada. Se puede especificar múltiples veces. + + + You need to rebuild the database using -reindex-chainstate to change -txindex + Necesita reconstruir la base de datos usando -reindex-chainstate para cambiar -txindex + + + %s corrupt, salvage failed + %s corrupto. Fracasó la recuperacion + + + -maxmempool must be at least %d MB + -maxmempool debe ser por lo menos de %d MB + + + <category> can be: + <category> puede ser: + + + Append comment to the user agent string + Adjunta un comentario a la linea de agente de usuario + + + Attempt to recover private keys from a corrupt wallet on startup + Intento de recuperar claves privadas de un monedero corrupto en arranque + + + Block creation options: + Opciones de creación de bloques: + + + Cannot resolve -%s address: '%s' + No se puede resolver -%s direccion: '%s' + + + Change index out of range + Cambio de indice fuera de rango + + + Connect only to the specified node(s) + Conectar sólo a los nodos (o nodo) especificados + + + Connection options: + Opciones de conexión: + + + Copyright (C) %i-%i + Copyright (C) %i-%i + + + Corrupted block database detected + Corrupción de base de datos de bloques detectada. + + + Debugging/Testing options: + Opciones de depuración/pruebas: + + + Do not load the wallet and disable wallet RPC calls + No cargar el monedero y desactivar las llamadas RPC del monedero + + + Do you want to rebuild the block database now? + ¿Quieres reconstruir la base de datos de bloques ahora? + + + Enable publish hash block in <address> + Activar publicar bloque .hash en <.Address> + + + Enable publish hash transaction in <address> + Activar publicar transacción .hash en <.Address> + + + Enable publish raw block in <address> + Habilita la publicacion de bloques en bruto en <direccion> + + + Enable publish raw transaction in <address> + Habilitar publicar transacción en rama en <dirección> + + + Enable transaction replacement in the memory pool (default: %u) + Habilita el reemplazamiento de transacciones en la piscina de memoria (predeterminado: %u) + + + Error initializing block database + Error al inicializar la base de datos de bloques + + + Error initializing wallet database environment %s! + Error al inicializar el entorno de la base de datos del monedero %s + + + Error loading %s + Error cargando %s + + + Error loading %s: Wallet corrupted + Error cargando %s: Monedero dañado + + + Error loading %s: Wallet requires newer version of %s + Error cargando %s: Monedero requiere un versión mas reciente de %s + + + Error loading %s: You can't disable HD on a already existing HD wallet + Error cargando %s: No puede deshabilitar HD en un monedero existente que ya es HD + + + Error loading block database + Error cargando base de datos de bloques + + + Error opening block database + Error al abrir base de datos de bloques. + + + Error: Disk space is low! + Error: ¡Espacio en disco bajo! + + + Failed to listen on any port. Use -listen=0 if you want this. + Ha fallado la escucha en todos los puertos. Use -listen=0 si desea esto. + + + Importing... + Importando... + + + Incorrect or no genesis block found. Wrong datadir for network? + Incorrecto o bloque de génesis no encontrado. Datadir equivocada para la red? + + + Initialization sanity check failed. %s is shutting down. + La inicialización de la verificación de validez falló. Se está apagando %s. + + + Invalid -onion address: '%s' + Dirección -onion inválida: '%s' + + + Invalid amount for -%s=<amount>: '%s' + Cantidad no valida para -%s=<amount>: '%s' + + + Invalid amount for -fallbackfee=<amount>: '%s' + Cantidad inválida para -fallbackfee=<amount>: '%s' + + + Keep the transaction memory pool below <n> megabytes (default: %u) + Mantener la memoria de transacciones por debajo de <n> megabytes (predeterminado: %u) + + + Loading banlist... + Cargando banlist... + + + Location of the auth cookie (default: data dir) + Ubicación de la cookie de autenticación (default: data dir) + + + Not enough file descriptors available. + No hay suficientes descriptores de archivo disponibles. + + + Only connect to nodes in network <net> (ipv4, ipv6 or onion) + Sólo conectar a nodos en redes <net> (ipv4, ipv6 o onion) + + + Print this help message and exit + Imprimir este mensaje de ayuda y salir + + + Print version and exit + Imprimir versión y salir + + + Prune cannot be configured with a negative value. + Pode no se puede configurar con un valor negativo. + + + Prune mode is incompatible with -txindex. + El modo recorte es incompatible con -txindex. + + + Rebuild chain state and block index from the blk*.dat files on disk + Reconstruir el estado de la cadena e indice de bloques a partir de los ficheros blk*.dat en disco + + + Rebuild chain state from the currently indexed blocks + Reconstruir el estado de la cadena a partir de los bloques indexados + + + Rewinding blocks... + Verificando bloques... + + + Set database cache size in megabytes (%d to %d, default: %d) + Asignar tamaño de cache en megabytes (entre %d y %d; predeterminado: %d) + + + Set maximum BIP141 block weight (default: %d) + Establecer peso máximo bloque BIP141 (predeterminado: %d) + + + Set maximum block size in bytes (default: %d) + Establecer tamaño máximo de bloque en bytes (predeterminado: %d) + + + Specify wallet file (within data directory) + Especificar archivo de monedero (dentro del directorio de datos) + + + Starting network threads... + Iniciando funciones de red... + + + The source code is available from %s. + El código fuente esta disponible desde %s. + + + Unable to bind to %s on this computer. %s is probably already running. + No se ha podido conectar con %s en este equipo. %s es posible que este todavia en ejecución. + + + Unsupported argument -benchmark ignored, use -debug=bench. + El argumento -benchmark no es soportado y ha sido ignorado, utiliza -debug=bench + + + Unsupported argument -debugnet ignored, use -debug=net. + Parámetros no compatibles -debugnet ignorados , use -debug = red. + + + Unsupported argument -tor found, use -onion. + Parámetros no compatibles -tor encontrados, use -onion . + + + Use UPnP to map the listening port (default: %u) + Usar UPnP para asignar el puerto de escucha (predeterminado:: %u) + + + User Agent comment (%s) contains unsafe characters. + El comentario del Agente de Usuario (%s) contiene caracteres inseguros. + + + Verifying blocks... + Verificando bloques... + + + Verifying wallet... + Verificando monedero... + + + Wallet %s resides outside data directory %s + El monedero %s se encuentra fuera del directorio de datos %s + + + Wallet debugging/testing options: + Opciones de depuración/pruebas de monedero: + + + Wallet needed to be rewritten: restart %s to complete + Es necesario reescribir el monedero: reiniciar %s para completar + + + Wallet options: + Opciones de monedero: + + + Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times + Permitir conexiones JSON-RPC de origen especificado. Válido para son una sola IP (por ejemplo 1.2.3.4), una red/máscara de red (por ejemplo 1.2.3.4/255.255.255.0) o una red/CIDR (e.g. 1.2.3.4/24). Esta opción se puede especificar varias veces + + + Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6 + Ligar a las direcciones especificadas y poner en lista blanca a los equipos conectados a ellas. Usar la notación para IPv6 [host]:puerto. + + + Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces) + Ligar a las direcciones especificadas para escuchar por conexiones JSON-RPC. Usar la notación para IPv6 [host]:puerto. Esta opción se puede especificar múltiples veces (por defecto: ligar a todas las interfaces) + + + Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality) + Crear nuevos archivos con permisos por defecto del sistema, en lugar de umask 077 (sólo efectivo con la funcionalidad de monedero desactivada) + + + Discover own IP addresses (default: 1 when listening and no -externalip or -proxy) + Descubra direcciones IP propias (por defecto: 1 cuando se escucha y nadie -externalip o -proxy) + + + Error: Listening for incoming connections failed (listen returned error %s) + Error: la escucha para conexiones entrantes falló (la escucha regresó el error %s) + + + Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message) + Ejecutar un comando cuando se reciba una alerta importante o cuando veamos un fork demasiado largo (%s en cmd se reemplazará por el mensaje) + + + Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) + Las comisiones (en %s/kB) mas pequeñas que esto se consideran como cero comisión para la retransmisión, minería y creación de la transacción (predeterminado: %s) + + + Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d) + Fuerza la retransmisión de transacciones desde nodos en la lista blanca incluso si violan la política de retransmisiones local (predeterminado: %d) + + + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) + Si el pago de comisión no está establecido, incluir la cuota suficiente para que las transacciones comiencen la confirmación en una media de n bloques ( por defecto :%u) + + + Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) + Cantidad no válida para -maxtxfee=<amount>: '%s' (debe ser por lo menos la cuota de comisión mínima de %s para prevenir transacciones atascadas) + + + Maximum size of data in data carrier transactions we relay and mine (default: %u) + El tamaño máximo de los datos en las operaciones de transporte de datos que transmitimos y el mio (default: %u) + + + Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect) + Consulta de direcciones pares mediante búsqueda de DNS, si bajo en direcciones (por defecto: 1 a menos que - conectar) + + + Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u) + Aleatorizar las credenciales para cada conexión proxy. Esto habilita la Tor stream isolation (por defecto: %u) + + + Set maximum size of high-priority/low-fee transactions in bytes (default: %d) + Establecer tamaño máximo de las transacciones de alta prioridad/baja comisión en bytes (predeterminado: %d) + + + The transaction amount is too small to send after the fee has been deducted + Monto de transacción muy pequeña luego de la deducción por comisión + + + This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. + Este producto incluye software desarrollado por el OpenSSL Project para su uso en OpenSSL Toolkit <https://www.openssl.org/>, software de cifrado escrito por Eric Young y software UPnP escrito por Thomas Bernard. + + + Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start + Usar tras BIP32 la generación de llave determinística jerárquica (HD) . Solo tiene efecto durante el primer inicio/generación del monedero + + + Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway + A los equipos en lista blanca no se les pueden prohibir los ataques DoS y sus transacciones siempre son retransmitidas, incluso si ya están en el mempool, es útil por ejemplo para un gateway. + + + You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain + Necesitas reconstruir la base de datos utilizando -reindex para volver al modo sin recorte. Esto volverá a descargar toda la cadena de bloques + + + (default: %u) + (por defecto: %u) + + + Accept public REST requests (default: %u) + Aceptar solicitudes públicas en FERIADOS (por defecto: %u) + + + Automatically create Tor hidden service (default: %d) + Automáticamente crea el servicio Tor oculto (por defecto: %d) + + + Connect through SOCKS5 proxy + Conectar usando SOCKS5 proxy + + + Error reading from database, shutting down. + Error al leer la base de datos, cerrando. + + + Imports blocks from external blk000??.dat file on startup + Importa los bloques desde un archivo externo blk000?.dat + + + Information + Información + + + Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) + Cantidad inválida para -paytxfee=<amount>: '%s' (debe ser por lo menos %s) + + + Invalid netmask specified in -whitelist: '%s' + Máscara de red inválida especificada en -whitelist: '%s' + + + Keep at most <n> unconnectable transactions in memory (default: %u) + Mantener como máximo <n> transacciones no conectables en memoria (por defecto: %u) + + + Need to specify a port with -whitebind: '%s' + Necesita especificar un puerto con -whitebind: '%s' + + + Node relay options: + Opciones de nodos de retransmisión: + + + RPC server options: + Opciones de servidor RPC: + + + Reducing -maxconnections from %d to %d, because of system limitations. + Reduciendo -maxconnections de %d a %d, debido a limitaciones del sistema. + + + Rescan the block chain for missing wallet transactions on startup + Rescanea la cadena de bloques para transacciones perdidas de la cartera + + + Send trace/debug info to console instead of debug.log file + Enviar información de trazas/depuración a la consola en lugar de al archivo debug.log + + + Send transactions as zero-fee transactions if possible (default: %u) + Mandar transacciones como comisión-cero si es posible (por defecto: %u) + + + Show all debugging options (usage: --help -help-debug) + Muestra todas las opciones de depuración (uso: --help -help-debug) + + + Shrink debug.log file on client startup (default: 1 when no -debug) + Reducir el archivo debug.log al iniciar el cliente (predeterminado: 1 sin -debug) + + + Signing transaction failed + Transacción falló + + + The transaction amount is too small to pay the fee + Cantidad de la transacción demasiado pequeña para pagar la comisión + + + This is experimental software. + Este software es experimental. + + + Tor control port password (default: empty) + Contraseña del puerto de control de Tor (predeterminado: vacio) + + + Tor control port to use if onion listening enabled (default: %s) + Puerto de control de Tor a utilizar si la escucha de onion esta activada (predeterminado: %s) + + + Transaction amount too small + Cantidad de la transacción demasiado pequeña + + + Transaction amounts must be positive + Las cantidades en las transacciones deben ser positivas + + + Transaction too large for fee policy + Operación demasiado grande para la política de tasas + + + Transaction too large + Transacción demasiado grande, intenta dividirla en varias. + + + Unable to bind to %s on this computer (bind returned error %s) + No es posible conectar con %s en este sistema (bind ha dado el error %s) + + + Upgrade wallet to latest format on startup + Actualizar el monedero al último formato al inicio + + + Username for JSON-RPC connections + Nombre de usuario para las conexiones JSON-RPC + + + + Warning + Aviso + + + Warning: unknown new rules activated (versionbit %i) + Advertencia: nuevas reglas desconocidas activadas (versionbit %i) + + + Whether to operate in a blocks only mode (default: %u) + Si se debe o no operar en un modo de solo bloques (predeterminado: %u) + + + Zapping all transactions from wallet... + Eliminando todas las transacciones del monedero... + + + ZeroMQ notification options: + Opciones de notificación ZeroQM: + + + Password for JSON-RPC connections + Contraseña para las conexiones JSON-RPC + + + + Execute command when the best block changes (%s in cmd is replaced by block hash) + Ejecutar un comando cuando cambia el mejor bloque (%s en cmd se sustituye por el hash de bloque) + + + Allow DNS lookups for -addnode, -seednode and -connect + Permitir búsquedas DNS para -addnode, -seednode y -connect + + + Loading addresses... + Cargando direcciones... + + + (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) + (1 = mantener los meta datos de transacción, por ejemplo: propietario e información de pago, 2 = omitir los metadatos) + + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + -maxtxfee tiene un ajuste muy elevado! Comisiones muy grandes podrían ser pagadas en una única transaccion. + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + -paytxfee tiene un valor muy elevado! La comisión de transacción que pagaras si envías una transaccion es alta. + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + No mantener transacciones en la memoria mas de <n> horas (predeterminado: %u) + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + Las comisiones (en %s/kB) menores que esto son consideradas de cero comision para la creacion de transacciones (predeterminado: %s) + + + How thorough the block verification of -checkblocks is (0-4, default: %u) + Nivel de rigor en la verificación de bloques de -checkblocks (0-4; predeterminado: %u) + + + Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u) + Mantener el índice completo de transacciones, usado por la llamada rpc de getrawtransaction (por defecto: %u) + + + Number of seconds to keep misbehaving peers from reconnecting (default: %u) + Número de segundos en que se evita la reconexión de pares con mal comportamiento (predeterminado: %u) + + + Output debugging information (default: %u, supplying <category> is optional) + Mostrar depuración (por defecto: %u, proporcionar <category> es opcional) + + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + Error: argumento -socks encontrado. El ajuste de la versión SOCKS ya no es posible, sólo proxies SOCKS5 son compatibles. + + + Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay. + El argumento no soportado -whitelistalwaysrelay ha sido ignorado, utiliza -whitelistrelay y/o -whitelistforcerelay. + + + Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) + Usar distintos proxys SOCKS5 para comunicarse vía Tor de forma anónima (Por defecto: %s) + + + Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. This option can be specified multiple times + Nombre de usuario y hash de la contraseña para las conexiones JSON-RPC. El campo <userpw> tiene el formato: <USERNAME>:<SALT>$<HASH>. Se incluye un script python convencional en share/rpcuser. Esta opción puede ser especificada multiples veces + + + Warning: Unknown block versions being mined! It's possible unknown rules are in effect + Advertencia: Se están minando versiones de bloques desconocidas! Es posible que normas desconocidas estén activas + + + 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. + Aviso: fichero 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. + + + (default: %s) + (predeterminado: %s) + + + Always query for peer addresses via DNS lookup (default: %u) + Siempre consultar direcciones de otros equipos por medio de DNS lookup (por defecto: %u) + + + How many blocks to check at startup (default: %u, 0 = all) + Cuántos bloques comprobar al iniciar (predeterminado: %u, 0 = todos) + + + Include IP addresses in debug output (default: %u) + Incluir direcciones IP en la salida de depuración (por defecto: %u) + + + Invalid -proxy address: '%s' + Dirección -proxy inválida: '%s' + + + Listen for JSON-RPC connections on <port> (default: %u or testnet: %u) + Escuchar conexiones JSON-RPC en <puerto> (predeterminado: %u o testnet: %u) + + + Listen for connections on <port> (default: %u or testnet: %u) + Escuchar conexiones en <puerto> (predeterminado: %u o testnet: %u) + + + Maintain at most <n> connections to peers (default: %u) + Mantener como máximo <n> conexiones a pares (predeterminado: %u) + + + Make the wallet broadcast transactions + Realiza las operaciones de difusión del monedero + + + Maximum per-connection receive buffer, <n>*1000 bytes (default: %u) + Búfer de recepción máximo por conexión, <n>*1000 bytes (por defecto: %u) + + + Maximum per-connection send buffer, <n>*1000 bytes (default: %u) + Búfer de recepción máximo por conexión, , <n>*1000 bytes (por defecto: %u) + + + Prepend debug output with timestamp (default: %u) + Anteponer marca temporal a la información de depuración (por defecto: %u) + + + Relay and mine data carrier transactions (default: %u) + Retransmitir y minar transacciones de transporte de datos (por defecto: %u) + + + Relay non-P2SH multisig (default: %u) + Relay non-P2SH multisig (default: %u) + + + Set key pool size to <n> (default: %u) + Ajustar el número de claves en reserva <n> (predeterminado: %u) + + + Set the number of threads to service RPC calls (default: %d) + Establecer el número de procesos para llamadas del servicio RPC (por defecto: %d) + + + Specify configuration file (default: %s) + Especificar archivo de configuración (por defecto: %s) + + + Specify connection timeout in milliseconds (minimum: 1, default: %d) + Especificar tiempo de espera de la conexión (mínimo: 1, por defecto: %d) + + + Specify pid file (default: %s) + Especificar archivo pid (predeterminado: %s) + + + Spend unconfirmed change when sending transactions (default: %u) + Usar cambio aún no confirmado al enviar transacciones (predeterminado: %u) + + + Threshold for disconnecting misbehaving peers (default: %u) + Umbral para la desconexión de pares con mal comportamiento (predeterminado: %u) + + + Unknown network specified in -onlynet: '%s' + La red especificada en -onlynet '%s' es desconocida + + + Insufficient funds + Fondos insuficientes + + + Loading block index... + Cargando el índice de bloques... + + + Add a node to connect to and attempt to keep the connection open + Añadir un nodo al que conectarse y tratar de mantener la conexión abierta + + + Loading wallet... + Cargando monedero... + + + Cannot downgrade wallet + No se puede cambiar a una versión mas antigua el monedero + + + Cannot write default address + No se puede escribir la dirección predeterminada + + + Rescanning... + Reexplorando... + + + Done loading + Se terminó de cargar + + + Error + Error + + \ No newline at end of file diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts index 5d2423eef..e65d4e6e4 100644 --- a/src/qt/locale/bitcoin_et.ts +++ b/src/qt/locale/bitcoin_et.ts @@ -41,10 +41,78 @@ &Delete &Kustuta - + + Choose the address to send coins to + Vali aadress millele mündid saata + + + Choose the address to receive coins with + Vali aadress müntide vastuvõtmiseks + + + C&hoose + V&ali + + + Sending addresses + Saatvad aadressid + + + Receiving addresses + Vastuvõtvad aadressid + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Need on sinu Bitcoin aadressid maksete saatmiseks. Ennem müntide saatmist kontrolli alati summat ja makse saaja aadressi. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Need on sinu Bitcoin aadressid sisenevate maksete vastu võtmiseks. Soovitav on iga tehingu tarbeks kasutada uut aadressi. + + + &Copy Address + &Kopeeri Aadress + + + Copy &Label + Kopeeri &Silt + + + &Edit + &Muuda + + + Export Address List + Ekspordi Aadresside Nimekiri + + + Comma separated file (*.csv) + Komadega eraldatud väärtuste fail (*.csv) + + + Exporting Failed + Eksport ebaõnnestus. + + + There was an error trying to save the address list to %1. Please try again. + Tõrge aadressi nimekirja salvestamisel %1. Palun proovi uuesti. + + AddressTableModel - + + Label + Märge + + + Address + Aadress + + + (no label) + (märge puudub) + + AskPassphraseDialog @@ -63,7 +131,87 @@ Repeat new passphrase Korda salafraasi - + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Sisesta uus salafraas rahakotti.<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/>. + + + Encrypt wallet + Krüpteeri rahakott + + + This operation needs your wallet passphrase to unlock the wallet. + Antud operatsioon vajab rahakoti lahtilukustamiseks salafraasi. + + + Unlock wallet + Ava rahakoti lukk + + + This operation needs your wallet passphrase to decrypt the wallet. + Antud operatsioon vajab rahakoti dekrüpteerimiseks salafraasi. + + + Decrypt wallet + Dekrüpteeri rahakott + + + Change passphrase + Vaheta salafraasi + + + Enter the old passphrase and new passphrase to the wallet. + Sisesta vana salafraas ja uus salafraas rahakotti. + + + Confirm wallet encryption + Kinnita rahakoti krüpteerimine. + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Hoiatus:Kui sa krüpteerid oma rahakoti ja kaotad salafraasi, siis sa<b>KAOTAD OMA BITCOINID</b>! + + + Are you sure you wish to encrypt your wallet? + Kas oled kindel, et soovid rahakoti krüpteerida? + + + Wallet encrypted + Rahakott krüpteeritud + + + Wallet encryption failed + Rahakoti krüpteerimine ebaõnnestus + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Rahakoti krüpteerimine ebaõnnestus sisemise tõrke tõttu. Sinu rahakott ei ole krüpteeritud. + + + The supplied passphrases do not match. + Sisestatud salafraasid ei kattu. + + + Wallet unlock failed + Rahakoti lahtilukustamine ebaõnnestus + + + The passphrase entered for the wallet decryption was incorrect. + Rahakoti dekrüpteerimiseks sisestatud salafraas ei ole õige. + + + Wallet decryption failed + Rahakoti dekrüpteerimine ebaõnnestus + + + Wallet passphrase was successfully changed. + Rahakoti salafraas on edukalt vahetatud. + + + Warning: The Caps Lock key is on! + Hoiatus:Klaviatuuri suurtähelukk on peal. + + BanTableModel @@ -101,6 +249,10 @@ Quit application Väljumine + + &About %1 + &Teave %1 + About &Qt Teave &Qt kohta @@ -147,7 +299,7 @@ &Debug window - &Debugimise aken + &Silumise aken Open debugging and diagnostic console @@ -171,7 +323,7 @@ &Receive - &Saama + &Võta vastu &Show / Hide @@ -209,10 +361,38 @@ Tabs toolbar Vahelehe tööriistariba + + Request payments (generates QR codes and bitcoin: URIs) + Loo maksepäring (genereerib QR koodid ja bitcoini: URId) + + + Open a bitcoin: URI or payment request + Ava bitcoini: URI või maksepäring + &Command-line options Käsurea valikud + + %n active connection(s) to Bitcoin network + %n aktiivne ühendus Bitcoini võrku%n aktiivset ühendust Bitcoini võrku + + + Indexing blocks on disk... + Kõvakettal olevate plokkide indekseerimine... + + + Processing blocks on disk... + Kõvakettal olevate plokkide töötlemine... + + + No block source available... + Plokkide allikas pole saadaval... + + + Processed %n block(s) of transaction history. + Töödeldud %n plokk transaktsioonide ajaloost.Töödeldud %n plokki transaktsioonide ajaloost. + %n hour(s) %n tund%n tundi @@ -261,9 +441,13 @@ Up to date Ajakohane + + %1 client + %1 klient + Catching up... - Jõuan... + Jõuan järgi... Date: %1 @@ -318,27 +502,183 @@ Quantity: Kogus: + + Bytes: + Baiti: + Amount: Summa: + + Priority: + Prioriteet + Fee: Tasu: + + Dust: + Puru: + + + After Fee: + Peale tehingutasu: + + + Change: + Vahetusraha: + + + Tree mode + Puu režiim + + + List mode + Loetelu režiim + Amount Kogus + + Received with label + Vastuvõetud märgisega + + + Received with address + Vastuvõetud aadressiga + Date Kuupäev + + Confirmations + Kinnitused + Confirmed Kinnitatud - + + Priority + Prioriteet + + + Copy address + Kopeeri aadress + + + Copy label + Kopeeri märgis + + + Copy amount + Kopeeri summa + + + Copy transaction ID + Kopeeri tehingu ID + + + Copy quantity + Kopeeri kogus + + + Copy fee + Kopeeri tehingutasu + + + Copy bytes + Kopeeri baidid + + + Copy priority + Kopeeri prioriteet + + + Copy dust + Kopeeri puru + + + Copy change + Kopeeri vahetusraha + + + highest + kõrgeim + + + higher + kõrgem + + + high + kõrge + + + medium-high + keskmiselt kõrge + + + medium + keskmine + + + low-medium + keskmiselt madal + + + low + madal + + + lower + madalam + + + lowest + madalaim + + + (%1 locked) + (%1 lukustatud) + + + none + puudub + + + yes + jah + + + no + ei + + + This label turns red if the transaction size is greater than 1000 bytes. + Märgis muutub punaseks kui transaktsiooni suurus ületab 1000 baiti. + + + This means a fee of at least %1 per kB is required. + See tähendab, et vajalik tehingutasu on vähemalt %1 kB kohta + + + This label turns red if the priority is smaller than "medium". + See märgis muutud punaseks kui prioriteet on madalam kui "keskmine". + + + (no label) + (märgis puudub) + + + (change) + (vahetusraha) + + EditAddressDialog @@ -353,7 +693,39 @@ &Address &Aadress - + + New receiving address + Uus vastu võttev aadress + + + New sending address + Uus saatev aadress + + + Edit receiving address + Muuda vastuvõtvat aadressi + + + Edit sending address + Muuda saatvat aadressi + + + The entered address "%1" is not a valid Bitcoin address. + Sisestatud aadress "%1" ei ole korrektne Bitcoin aadress. + + + The entered address "%1" is already in the address book. + Sisestatud aadress "%1" on juba aadressi raamatus. + + + Could not unlock wallet. + Rahakoti lahtilukustamine ebaõnnestus. + + + New key generation failed. + Uue võtme genereerimine ebaõnnestus. + + FreespaceChecker @@ -379,6 +751,14 @@ command-line options käsurea valikud + + UI Options: + Kasutajaliidese Suvandid: + + + Show splash screen on startup (default: %u) + Käivitamisel kuva laadimisekraani (vaikimisi %u) + Intro @@ -401,7 +781,15 @@ URI: URI: - + + Select payment request file + Vali maksepäringu fail + + + Select payment request file to open + Vali maksepäringu fail mida avada + + OptionsDialog @@ -500,6 +888,10 @@ default vaikeväärtus + + none + puudub + Confirm options reset Kinnita valikute algseadistamine @@ -519,6 +911,10 @@ 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. Kuvatav info ei pruugi olla ajakohane. Ühenduse loomisel süngitakse sinu rahakott automaatselt Bitconi võrgustikuga, kuid see toiming on hetkel lõpetamata. + + Pending: + Ootel: + Immature: Ebaküps: @@ -527,6 +923,10 @@ Mined balance that has not yet matured Mitte aegunud mine'itud jääk + + Total: + Kokku: + Recent transactions Hiljutised tehingud @@ -534,6 +934,22 @@ PaymentServer + + Payment request error + Maksepäringu tõrge + + + Payment request rejected + Maksepäring tagasi lükatud + + + Payment request expired. + Maksepäring aegunud. + + + Unverified payment requests to custom payment scripts are unsupported. + Kinnitamata maksepäringud kohandatud makse scriptidele ei ole toetatud. + PeerTableModel @@ -551,6 +967,10 @@ QRImageWidget + + Save QR Code + Salvesta QR Kood + RPCConsole @@ -574,6 +994,10 @@ General Üldine + + Using BerkeleyDB version + Kasutab BerkeleyDB versiooni + Startup time Käivitamise hetk @@ -598,6 +1022,10 @@ Current number of blocks Plokkide hetkearv + + Memory usage + Mälu kasutus + Received Vastuvõetud @@ -614,6 +1042,14 @@ Version Versioon + + Synced Headers + Sünkroniseeritud Päised + + + Synced Blocks + Sünkroniseeritud Plokid + Services Teenused @@ -632,7 +1068,7 @@ Debug log file - Debugimise logifail + Silumise logifail Clear console @@ -662,7 +1098,27 @@ %1 GB %1 GB - + + Inbound + Sisenev + + + Outbound + Väljuv + + + Yes + Jah + + + No + Ei + + + Unknown + Teadmata + + ReceiveCoinsDialog @@ -677,6 +1133,10 @@ &Message: &Sõnum: + + Clear all fields of the form. + Puhasta kõik vormi väljad. + Show Näita @@ -685,16 +1145,76 @@ Remove Eemalda - + + Copy label + Kopeeri märgis + + + Copy message + Kopeeri sõnum + + + Copy amount + Kopeeri summa + + ReceiveRequestDialog + + QR Code + QR Kood + Copy &Address &Kopeeri Aadress + + Payment information + Makse Informatsioon + + + Address + Aadress + + + Amount + Summa + + + Label + Silt + + + Message + Sõnum + + + Resulting URI too long, try to reduce the text for label / message. + URI liiga pikk, proovi vähendada märke / sõnumi pikkust. + RecentRequestsTableModel + + Date + Kuupäev + + + Label + Silt + + + Message + Sõnum + + + (no label) + (märge puudub) + + + (no message) + (sõnum puudub) + SendCoinsDialog @@ -702,6 +1222,14 @@ Send Coins Müntide saatmine + + Inputs... + Sisendid... + + + automatically selected + automaatselt valitud + Insufficient funds! Liiga suur summa @@ -710,14 +1238,30 @@ Quantity: Kogus: + + Bytes: + Baiti: + Amount: Summa: + + Priority: + Prioriteet + Fee: Tasu: + + After Fee: + Peale tehingutasu: + + + Change: + Vahetusraha: + Transaction Fee: Tehingu tasu: @@ -726,6 +1270,10 @@ Choose... Vali... + + per kilobyte + kilobaidi kohta + Hide Peida @@ -734,6 +1282,10 @@ Recommended: Soovitatud: + + Confirmation time: + Kinnitamise aeg: + normal normaalne @@ -750,6 +1302,14 @@ Add &Recipient Lisa &Saaja + + Clear all fields of the form. + Puhasta kõik vormi väljad. + + + Dust: + Puru: + Clear &All Puhasta &Kõik @@ -766,7 +1326,63 @@ S&end S&aada - + + Copy quantity + Kopeeri kogus + + + Copy amount + Kopeeri summa + + + Copy fee + Kopeeri tehingutasu + + + Copy bytes + Kopeeri baidid + + + Copy priority + Kopeeri prioriteet + + + Copy dust + Kopeeri puru + + + Copy change + Kopeeri vahetusraha + + + Are you sure you want to send? + Oled kindel, et soovid saata? + + + added as transaction fee + lisatud kui tehingutasu + + + or + või + + + The recipient address is not valid. Please recheck. + Saaja aadress ei ole korrektne. Palun kontrolli üle. + + + Payment request expired. + Maksepäring aegunud. + + + Warning: Invalid Bitcoin address + Hoiatus: Ebakorrektne Bitcoin aadress + + + (no label) + (märgis puudub) + + SendCoinsEntry @@ -781,6 +1397,10 @@ &Label: &Märgis + + Choose previously used address + Vali eelnevalt kasutatud aadress + Alt+A Alt+A @@ -793,6 +1413,10 @@ Alt+P Alt+P + + S&ubtract fee from amount + L&ahuta tehingutasu summast + Message: Sõnum: @@ -804,10 +1428,22 @@ SendConfirmationDialog - + + Yes + Jah + + ShutdownWindow - + + %1 is shutting down... + %1 lülitub välja... + + + Do not shut down the computer until this window disappears. + Ära lülita arvutit välja ennem kui see aken on kadunud. + + SignVerifyMessageDialog @@ -818,6 +1454,14 @@ &Sign Message &Allkirjastamise teade + + The Bitcoin address to sign the message with + Bitcoin aadress millega sõnum allkirjastada + + + Choose previously used address + Vali eelnevalt kasutatud aadress + Alt+A Alt+A @@ -862,6 +1506,10 @@ &Verify Message &Kinnita Sõnum + + The Bitcoin address the message was signed with + Bitcoin aadress millega sõnum on allkirjastatud + Verify the message to ensure it was signed with the specified Bitcoin address Kinnita sõnum tõestamaks selle allkirjastatust määratud Bitcoini aadressiga. @@ -874,7 +1522,55 @@ Reset all verify message fields Tühjenda kõik sõnumi kinnitamise väljad - + + Click "Sign Message" to generate signature + Allkirja loomiseks vajuta "Allkirjasta Sõnum" + + + The entered address is invalid. + Sisestatud aadress ei ole korrektne + + + Please check the address and try again. + Palun kontrolli aadressi ja proovi uuesti. + + + Wallet unlock was cancelled. + Rahakoti lahtilukustamine on katkestatud. + + + Private key for the entered address is not available. + Sisestatud aadressi privaatvõti pole saadaval. + + + Message signing failed. + Sõnumi allkirjastamine ebaõnnestus. + + + Message signed. + Sõnum allkirjastatud + + + The signature could not be decoded. + Allkirja polnud võimalik dekodeerida. + + + Please check the signature and try again. + Palun kontrolli allkirja ja proovi uuesti. + + + The signature did not match the message digest. + Allkiri ei vastanud sõnumi krüptoräsile. + + + Message verification failed. + Sõnumi verifitseerimine ebaõnnestus. + + + Message verified. + Sõnum verifitseeritud. + + SplashScreen @@ -891,7 +1587,67 @@ TransactionDesc - + + %1/unconfirmed + %1/kinnitamata + + + %1 confirmations + %1 kinnitust + + + Status + Olek + + + Date + Kuupäev + + + Generated + Genereeritud + + + label + märgis + + + not accepted + pole vastu võetud + + + Transaction fee + Tehingutasu + + + Message + Sõnum + + + Comment + Kommentaar + + + Merchant + Kaupleja + + + Inputs + Sisendid + + + Amount + Summa + + + true + tõene + + + false + väär + + TransactionDescDialog @@ -901,9 +1657,105 @@ TransactionTableModel + + Date + Kuupäev + + + Type + Tüüp + + + Label + Silt + + + Unconfirmed + Kinnitamata + + + (no label) + (silt puudub) + TransactionView + + All + Kõik + + + Today + Täna + + + This week + Käesolev nädal + + + This month + Käesolev kuu + + + Last month + Eelmine kuu + + + This year + Käesolev aasta + + + Range... + Vahemik... + + + Min amount + Minimaalne summa + + + Copy address + Kopeeri aadress + + + Copy label + Kopeeri märgis + + + Copy amount + Kopeeri summa + + + Copy transaction ID + Kopeeri tehingu ID + + + Comma separated file (*.csv) + Komadega eraldatud väärtuste fail (*.csv) + + + Date + Kuupäev + + + Type + Tüüp + + + Label + Silt + + + Address + Aadress + + + ID + ID + + + Exporting Failed + Eksport ebaõnnestus. + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts index a02c2dd9a..5a31ff591 100644 --- a/src/qt/locale/bitcoin_fa.ts +++ b/src/qt/locale/bitcoin_fa.ts @@ -41,10 +41,50 @@ &Delete &حذف + + Choose the address to send coins to + آدرس مورد نظر برای ارسال کوین ها را انتخاب کنید + + + Choose the address to receive coins with + آدرس موردنظر برای دریافت کوین ها را انتخاب کنید. + + + C&hoose + انتخاب + + + Sending addresses + آدرس های فرستنده + + + Receiving addresses + آدرس های گیرنده + + + Copy &Label + کپی و برچسب‌&گذاری + + + &Edit + &ویرایش + AddressTableModel - + + Label + برچسب + + + Address + آدرس + + + (no label) + (بدون برچسب) + + AskPassphraseDialog @@ -63,7 +103,55 @@ Repeat new passphrase تکرار گذرواژهٔ جدید - + + Encrypt wallet + رمزنگاری کیف پول + + + Unlock wallet + باز کردن قفل کیف پول + + + Decrypt wallet + رمزگشایی کیف پول + + + Confirm wallet encryption + تأیید رمزنگاری کیف پول + + + Are you sure you wish to encrypt your wallet? + آیا مطمئن هستید که می‌خواهید کیف پول خود را رمزنگاری کنید؟ + + + Wallet encrypted + کیف پول رمزنگاری شد + + + Wallet encryption failed + رمزنگاری کیف پول با شکست مواجه شد + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + رمزنگاری کیف پول بنا به یک خطای داخلی با شکست مواجه شد. کیف پول شما رمزنگاری نشد. + + + Wallet unlock failed + بازگشایی قفل کیف‌پول با شکست مواجه شد + + + Wallet decryption failed + رمزگشایی کیف پول با شکست مواجه شد + + + Wallet passphrase was successfully changed. + گذرواژهٔ کیف پول با موفقیت عوض شد. + + + Warning: The Caps Lock key is on! + هشدار: کلید Caps Lock روشن است! + + BanTableModel @@ -133,6 +221,10 @@ &Options... &تنظیمات... + + Modify configuration options for %1 + تغییر تنظیمات %1 + &Encrypt Wallet... &رمزنگاری کیف پول... @@ -237,6 +329,10 @@ Tabs toolbar نوارابزار برگه‌ها + + Request payments (generates QR codes and bitcoin: URIs) + درخواست پرداخت ( تولید کد کیوار و ادرس بیت کوین) + Show the list of used sending addresses and labels نمایش لیست آدرس های ارسال و لیبل ها @@ -257,10 +353,18 @@ %n active connection(s) to Bitcoin network %n ارتباط فعال با شبکهٔ بیت‌کوین + + Processing blocks on disk... + پردازش بلوک‌ها روی دیسک... + No block source available... منبعی برای دریافت بلاک در دسترس نیست... + + Processed %n block(s) of transaction history. + پردازش %n بلاک از تاریخچه ی تراکنش ها + %n hour(s) %n ساعت @@ -434,7 +538,99 @@ Priority اولویت - + + Copy label + کپی برچسب + + + Copy amount + کپی مقدار + + + Copy transaction ID + کپی شناسهٔ تراکنش + + + Lock unspent + قفل کردن خرج نشده ها + + + Unlock unspent + بازکردن قفل خرج نشده ها + + + Copy quantity + کپی تعداد + + + highest + بیشترین + + + higher + بیشتر + + + high + زیاد + + + medium-high + متوسط رو به بالا + + + medium + متوسط + + + low-medium + متوسط متمایل به کم + + + low + کم + + + lower + کمتر + + + lowest + کمترین + + + (%1 locked) + (%1 قفل شده) + + + none + هیچکدام + + + yes + بله + + + no + خیر + + + This label turns red if the transaction size is greater than 1000 bytes. + اگر حجم تراکنش از 1000 بایت بیشتر شود برچسب قرمز می شود. + + + Can vary +/- 1 byte per input. + ممکن است +/- 1 بایت در ورودی تفاوت داشته باشد. + + + (no label) + (بدون برچسب) + + + (change) + (تغییر) + + EditAddressDialog @@ -449,6 +645,34 @@ &Address &نشانی + + New receiving address + نشانی گیرنده جدید + + + New sending address + نشانی فرستنده جدید + + + Edit receiving address + ویرایش آدرس گیرنده + + + Edit sending address + ویرایش آدرس قرستنده + + + The entered address "%1" is not a valid Bitcoin address. + نشانی وارد شده "%1" یک نشانی معتبر بیت‌کوین نیست. + + + The entered address "%1" is already in the address book. + نشانی وارد شده «%1» در حال حاضر در دفترچه وجود دارد. + + + Could not unlock wallet. + نمی‌توان کیف پول را رمزگشایی کرد. + FreespaceChecker @@ -499,6 +723,18 @@ UI Options: گزینه‌های رابط کاربری: + + Set language, for example "de_DE" (default: system locale) + زبان را تنظیم کنید؛ برای مثال «de_DE» (پیشفرض: زبان سیستم) + + + Start minimized + شروع برنامه به صورت کوچک‌شده + + + Set SSL root certificates for payment request (default: -system-) + تنظیم گواهی ریشه SSl برای درخواست پرداخت (پیشفرض: -system-) + Show splash screen on startup (default: %u) نمایش پنجرهٔ خوشامدگویی در ابتدای اجرای برنامه (پیش‌فرض: %u) @@ -537,6 +773,14 @@ Open URI بازکردن آدرس + + Open payment request from URI or file + بازکردن درخواست پرداخت از آدرس یا فایل + + + URI: + آدرس اینترنتی: + Select payment request file انتخاب فایل درخواست پرداخت @@ -552,6 +796,10 @@ &Main &عمومی + + Automatically start %1 after logging in to the system. + اجرای خودکار %1 بعد زمان ورود به سیستم. + MB مگابایت @@ -981,7 +1229,15 @@ Remove حذف کردن - + + Copy label + کپی برچسب + + + Copy amount + کپی مقدار + + ReceiveRequestDialog @@ -996,9 +1252,25 @@ &Save Image... &ذخیره عکس... + + Address + آدرس + + + Label + برچسب + RecentRequestsTableModel + + Label + برچسب + + + (no label) + (بدون برچسب) + SendCoinsDialog @@ -1114,7 +1386,19 @@ S&end &ارسال - + + Copy quantity + کپی تعداد + + + Copy amount + کپی مقدار + + + (no label) + (بدون برچسب) + + SendCoinsEntry @@ -1285,9 +1569,37 @@ TransactionTableModel + + Label + برچسب + + + (no label) + (بدون برچسب) + TransactionView + + Copy label + کپی برچسب + + + Copy amount + کپی مقدار + + + Copy transaction ID + کپی شناسهٔ تراکنش + + + Label + برچسب + + + Address + آدرس + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts index 4d33a58bf..30a9fa3c0 100644 --- a/src/qt/locale/bitcoin_fr.ts +++ b/src/qt/locale/bitcoin_fr.ts @@ -91,7 +91,7 @@ Exporting Failed - L'exportation a échoué + Échec d'exportation There was an error trying to save the address list to %1. Please try again. @@ -133,7 +133,7 @@ Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. - Saisissez une nouvelle phrase de passe pour le portefeuille.<br/>Veuillez utiliser une phrase composée de <b>dix caractères aléatoires ou plus</b>, ou bien de <b>huit mots ou plus</b>. + Saisissez la nouvelle phrase de passe du porte-monnaie.<br/>Veuillez utiliser une phrase de passe composée de <b>dix caractères aléatoires ou plus</b>, ou de <b>huit mots ou plus</b>. Encrypt wallet @@ -159,7 +159,67 @@ Change passphrase Changer la phrase de passe - + + Enter the old passphrase and new passphrase to the wallet. + Saisir l'ancienne puis la nouvelle phrase de passe du porte-monnaie. + + + Confirm wallet encryption + Confirmer le chiffrement du porte-monnaie + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Avertissement : si vous chiffrez votre porte-monnaie et perdez votre phrase de passe, vous <b>PERDREZ TOUS VOS BITCOINS</b> ! + + + Are you sure you wish to encrypt your wallet? + Voulez-vous vraiment chiffrer votre porte-monnaie ? + + + Wallet encrypted + Le porte-monnaie est chiffré + + + %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + %1 va maintenant se fermer pour terminer le processus de chiffrement. Souvenez-vous que le chiffrement de votre porte-monnaie ne peut pas protéger entièrement vos bitcoins contre le vol par des logiciels malveillants qui infecteraient votre ordinateur. + + + IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet. + IMPORTANT : toutes les sauvegardes précédentes du fichier de votre porte-monnaie devraient être remplacées par le fichier du porte-monnaie chiffré nouvellement généré. Pour des raisons de sécurité, les sauvegardes précédentes de votre fichier de porte-monnaie non chiffré deviendront inutilisables dès que vous commencerez à utiliser le nouveau porte-monnaie chiffré. + + + Wallet encryption failed + Échec de chiffrement du porte-monnaie + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Le chiffrement du porte-monnaie a échoué en raison d'une erreur interne. Votre porte-monnaie n'a pas été chiffré. + + + The supplied passphrases do not match. + Les phrases de passe saisies ne correspondent pas. + + + Wallet unlock failed + Échec de déverrouillage du porte-monnaie + + + The passphrase entered for the wallet decryption was incorrect. + La phrase de passe saisie pour déchiffrer le porte-monnaie était erronée. + + + Wallet decryption failed + Échec de déchiffrement du porte-monnaie + + + Wallet passphrase was successfully changed. + La phrase de passe du porte-monnaie a été modifiée avec succès. + + + Warning: The Caps Lock key is on! + Avertissement : la touche Verr. Maj. est activée ! + + BanTableModel @@ -175,7 +235,7 @@ BitcoinGUI Sign &message... - &Signer le message... + Signer un &message... Synchronizing with network... @@ -199,7 +259,7 @@ Browse transaction history - Parcourir l'historique des transactions + Parcourir l'historique transactionnel E&xit @@ -303,15 +363,15 @@ &Show / Hide - &Afficher / Masquer + &Afficher / cacher Show or hide the main Window - Afficher ou masquer la fenêtre principale + Afficher ou cacher la fenêtre principale Encrypt the private keys that belong to your wallet - Chiffrer les clefs privées de votre porte-monnaie + Chiffrer les clés privées qui appartiennent à votre porte-monnaie Sign messages with your Bitcoin addresses to prove you own them @@ -351,7 +411,7 @@ Open a bitcoin: URI or payment request - Ouvrir un URI bitcoin: ou une demande de paiement + Ouvrir une URI bitcoin: ou une demande de paiement &Command-line options @@ -399,7 +459,7 @@ %1 behind - en retard d'%1 + en retard de %1 Last received block was generated %1 ago. @@ -562,11 +622,151 @@ Priority Priorité + + Copy address + Copier l’adresse + + + Copy label + Copier l’étiquette + + + Copy amount + Copier le montant + + + Copy transaction ID + Copier l'ID de la transaction + + + Lock unspent + Verrouiller les transactions non dépensées + + + Unlock unspent + Déverrouiller les transactions non dépensées + + + Copy quantity + Copier la quantité + + + Copy fee + Copier les frais + + + Copy after fee + Copier après les frais + + + Copy bytes + Copier les octets + + + Copy priority + Copier la priorité + + + Copy dust + Copier la poussière + + + Copy change + Copier la monnaie + + + highest + la plus élevée + + + higher + plus élevée + + + high + élevée + + + medium-high + moyenne-élevée + + + medium + moyenne + + + low-medium + faible-moyenne + + + low + faible + + + lower + plus faible + + + lowest + la plus faible + + + (%1 locked) + (%1 verrouillée) + + + none + aucune + + + yes + oui + + + no + non + + + This label turns red if the transaction size is greater than 1000 bytes. + Cette étiquette devient rouge si la taille de la transaction dépasse 1 000 octets. + + + This means a fee of at least %1 per kB is required. + Cela signifie que des frais d'au moins %1 sont exigés par Ko. + + + Can vary +/- 1 byte per input. + Peut varier +/- 1 octet par entrée. + + + Transactions with higher priority are more likely to get included into a block. + Les transactions à priorité élevée on plus de chance d'être incluses dans un bloc. + + + This label turns red if the priority is smaller than "medium". + Cette étiquette devient rouge si la priorité est plus basse que « moyenne ». + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Cette étiquette devient rouge si un destinataire reçoit un montant inférieur au seuil actuel de poussière. + + + Can vary +/- %1 satoshi(s) per input. + Peut varier +/- %1 satoshi(s) par entrée. + (no label) (aucune étiquette) - + + change from %1 (%2) + monnaie de %1 (%2) + + + (change) + (monnaie) + + EditAddressDialog @@ -589,7 +789,39 @@ &Address &Adresse - + + New receiving address + Nouvelle adresse de réception + + + New sending address + Nouvelle adresse d’envoi + + + Edit receiving address + Modifier l’adresse de réception + + + Edit sending address + Modifier l’adresse d'envoi + + + The entered address "%1" is not a valid Bitcoin address. + L'adresse saisie « %1 » n'est pas une adresse Bitcoin valide. + + + The entered address "%1" is already in the address book. + L’adresse saisie « %1 » est déjà présente dans le carnet d'adresses. + + + Could not unlock wallet. + Impossible de déverrouiller le porte-monnaie. + + + New key generation failed. + Échec de génération de la nouvelle clé. + + FreespaceChecker @@ -729,7 +961,11 @@ Select payment request file Choisir le fichier de demande de paiement - + + Select payment request file to open + Choisir le fichier de demande de paiement à ouvrir + + OptionsDialog @@ -1042,7 +1278,95 @@ PaymentServer - + + Payment request error + Erreur de demande de paiement + + + Cannot start bitcoin: click-to-pay handler + Impossible de démarrer le gestionnaire de cliquer-pour-payer bitcoin: + + + URI handling + Gestion des URI + + + Payment request fetch URL is invalid: %1 + L'URL de récupération de la demande de paiement est invalide : %1 + + + Invalid payment address %1 + Adresse de paiement invalide %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + 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. + + + Payment request file handling + Gestion des fichiers de demande de paiement + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + Le fichier de demande de paiement ne peut pas être lu ! Cela peut être causé par un fichier de demande de paiement invalide. + + + Payment request rejected + Demande de paiement rejetée + + + Payment request network doesn't match client network. + Le réseau de la demande de paiement ne correspond pas au réseau du client. + + + Payment request expired. + La demande de paiement a expiré + + + Payment request is not initialized. + La demande de paiement n'est pas initialisée. + + + Unverified payment requests to custom payment scripts are unsupported. + Les demandes de paiements non vérifiées vers des scripts de paiement personnalisés ne sont pas prises en charge. + + + Invalid payment request. + Demande de paiement invalide. + + + Requested payment amount of %1 is too small (considered dust). + Le paiement demandé d'un montant de %1 est trop faible (considéré comme de la poussière). + + + Refund from %1 + Remboursement de %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + La demande de paiement %1 est trop grande (%2 octets, %3 octets permis). + + + Error communicating with %1: %2 + Erreur de communication avec %1 : %2 + + + Payment request cannot be parsed! + La demande de paiement ne peut pas être analysée ! + + + Bad response from server %1 + Mauvaise réponse du serveur %1 + + + Network request error + Erreur de demande réseau + + + Payment acknowledged + Le paiement a été confirmé + + PeerTableModel @@ -1099,7 +1423,23 @@ QRImageWidget - + + &Save Image... + &Enregistrer l'image... + + + &Copy Image + &Copier l'image + + + Save QR Code + Enregistrer le code QR + + + PNG Image (*.png) + Image PNG (*.png) + + RPCConsole @@ -1216,7 +1556,7 @@ Open the %1 debug log file from the current data directory. This can take a few seconds for large log files. - Ouvrir le journal de débogage de %1 depuis le répertoire de données actuel. Ceci peut prendre quelques secondes pour les journaux de grande taille. + 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. Decrease font size @@ -1461,7 +1801,19 @@ Remove Retirer - + + Copy label + Copier l’étiquette + + + Copy message + Copier le message + + + Copy amount + Copier le montant + + ReceiveRequestDialog @@ -1480,26 +1832,74 @@ &Save Image... &Enregistrer l'image... + + Request payment to %1 + Demande de paiement à %1 + + + Payment information + Informations de paiement + + + URI + URI + Address Adresse + + Amount + Montant + Label Étiquette - + + Message + Message + + + Resulting URI too long, try to reduce the text for label / message. + L'URI résultante est trop longue. Essayez de réduire le texte de l'étiquette ou du message. + + + Error encoding URI into QR Code. + Erreur d'encodage de l'URI en code QR. + + RecentRequestsTableModel + + Date + Date + Label Étiquette + + Message + Message + (no label) (aucune étiquette) - + + (no message) + (aucun message) + + + (no amount requested) + (aucun montant demandé) + + + Requested + Demandée + + SendCoinsDialog @@ -1651,79 +2051,183 @@ E&nvoyer - (no label) - (aucune étiquette) + Copy quantity + Copier la quantité - - - SendCoinsEntry - A&mount: - &Montant : + Copy amount + Copier le montant - Pay &To: - &Payer à : + Copy fee + Copier les frais - &Label: - É&tiquette : + Copy after fee + Copier après les frais - Choose previously used address - Choisir une adresse déjà utilisée + Copy bytes + Copier les octets - This is a normal payment. - Ceci est un paiement normal. + Copy priority + Copier la priorité - The Bitcoin address to send the payment to - L'adresse Bitcoin à laquelle envoyer le paiement + Copy dust + Copier la poussière - Alt+A - Alt+A + Copy change + Copier la monnaie - Paste address from clipboard - Coller l'adresse du presse-papiers + %1 to %2 + %1 à %2 - Alt+P - Alt+P + Are you sure you want to send? + Voulez-vous vraiment envoyer ? - Remove this entry - Retirer cette entrée + added as transaction fee + ajoutés comme frais de transaction - 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. - 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.. + Total Amount %1 + Montant total %1 - S&ubtract fee from amount - S&oustraire les frais du montant + or + ou - Message: - Message : + Confirm send coins + Confirmer l’envoi de pièces - This is an unauthenticated payment request. - Cette demande de paiement n'est pas authentifiée. + The recipient address is not valid. Please recheck. + L'adresse du destinataire est invalide. Veuillez la revérifier. - This is an authenticated payment request. - Cette demande de paiement est authentifiée. + The amount to pay must be larger than 0. + Le montant à payer doit être supérieur à 0. - Enter a label for this address to add it to the list of used addresses - Saisir une étiquette pour cette adresse afin de l'ajouter à la liste d'adresses utilisées + The amount exceeds your balance. + Le montant dépasse votre solde. - 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. - 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. + The total exceeds your balance when the %1 transaction fee is included. + Le montant dépasse votre solde lorsque les frais de transaction de %1 sont inclus. + + + Duplicate address found: addresses should only be used once each. + Adresse identique trouvée : chaque adresse ne devrait être utilisée qu'une fois. + + + Transaction creation failed! + Échec de création de la transaction ! + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + La transaction a été rejetée ! Cela peut arriver si certaines pièces de votre porte-monnaie étaient déjà dépensées, par exemple si vous avez utilisé une copie de wallet.dat et que des pièces ont été dépensées dans la copie sans être marquées comme telles ici. + + + A fee higher than %1 is considered an absurdly high fee. + Des frais supérieurs à %1 sont considérés comme ridiculement élevés. + + + Payment request expired. + La demande de paiement a expiré + + + Pay only the required fee of %1 + Payer seulement les frais exigés de %1 + + + Warning: Invalid Bitcoin address + Avertissement : adresse Bitcoin invalide + + + Warning: Unknown change address + Avertissement : adresse de monnaie rendue inconnue + + + (no label) + (aucune étiquette) + + + + SendCoinsEntry + + A&mount: + &Montant : + + + Pay &To: + &Payer à : + + + &Label: + É&tiquette : + + + Choose previously used address + Choisir une adresse déjà utilisée + + + This is a normal payment. + Ceci est un paiement normal. + + + The Bitcoin address to send the payment to + L'adresse Bitcoin à laquelle envoyer le paiement + + + Alt+A + Alt+A + + + Paste address from clipboard + Coller l'adresse du presse-papiers + + + Alt+P + Alt+P + + + Remove this entry + Retirer cette entrée + + + 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. + 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.. + + + S&ubtract fee from amount + S&oustraire les frais du montant + + + Message: + Message : + + + This is an unauthenticated payment request. + Cette demande de paiement n'est pas authentifiée. + + + This is an authenticated payment request. + Cette demande de paiement est authentifiée. + + + Enter a label for this address to add it to the list of used addresses + Saisir une étiquette pour cette adresse afin de l'ajouter à la liste d'adresses utilisées + + + 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. + 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. Pay To: @@ -1733,10 +2237,18 @@ Memo: Mémo : - + + Enter a label for this address to add it to your address book + Saisir une étiquette pour cette adresse afin de l’ajouter à votre carnet d’adresses + + SendConfirmationDialog - + + Yes + Oui + + ShutdownWindow @@ -1760,7 +2272,7 @@ 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. - Vous pouvez signer des messages/accords avec vos adresses pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Faites attention de ne rien signer de vague ou au hasard, car des attaques d'hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l'usurper. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous êtes d'accord. + Vous pouvez signer des messages ou des accords avec vos adresses pour prouver que vous pouvez recevoir des bitcoins à ces dernières. Faites attention de ne rien signer de vague ou au hasard, car des attaques d'hameçonnage pourraient essayer de vous faire signer avec votre identité afin de l'usurper. Ne signez que des déclarations entièrement détaillées et avec lesquelles vous êtes d'accord. The Bitcoin address to sign the message with @@ -1834,7 +2346,59 @@ Reset all verify message fields Réinitialiser tous les champs de vérification de message - + + Click "Sign Message" to generate signature + Cliquez sur « Signer le message » pour générer la signature + + + The entered address is invalid. + L'adresse saisie est invalide. + + + Please check the address and try again. + Veuillez vérifier l'adresse et ressayer. + + + The entered address does not refer to a key. + L'adresse saisie ne fait pas référence à une clé. + + + Wallet unlock was cancelled. + Le déverrouillage du porte-monnaie a été annulé. + + + Private key for the entered address is not available. + La clé privée n'est pas disponible pour l'adresse saisie. + + + Message signing failed. + Échec de signature du message. + + + Message signed. + Le message a été signé. + + + The signature could not be decoded. + La signature n'a pu être décodée. + + + Please check the signature and try again. + Veuillez vérifier la signature et ressayer. + + + The signature did not match the message digest. + La signature ne correspond pas au condensé du message. + + + Message verification failed. + Échec de vérification du message. + + + Message verified. + Le message a été vérifié. + + SplashScreen @@ -1851,31 +2415,419 @@ TransactionDesc - + + Open for %n more block(s) + Ouvert pour %n bloc de plusOuvert pour %n blocs de plus + + + Open until %1 + Ouvert jusqu'à %1 + + + conflicted with a transaction with %1 confirmations + est en conflit avec une transaction ayant %1 confirmations + + + %1/offline + %1/hors ligne + + + 0/unconfirmed, %1 + 0/non confirmées, %1 + + + in memory pool + dans la réserve de mémoire + + + not in memory pool + pas dans la réserve de mémoire + + + abandoned + abandonnée + + + %1/unconfirmed + %1/non confirmée + + + %1 confirmations + %1 confirmations + + + Status + État + + + , has not been successfully broadcast yet + , n’a pas encore été diffusée avec succès + + + , broadcast through %n node(s) + , diffusée à travers %n nœud, diffusée à travers %n nœuds + + + Date + Date + + + Source + Source + + + Generated + Générée + + + From + De + + + unknown + inconnue + + + To + À + + + own address + votre adresse + + + watch-only + juste-regarder + + + label + étiquette + + + Credit + Crédit + + + matures in %n more block(s) + arrive à maturité dans %n bloc de plusarrive à maturité dans %n blocs de plus + + + not accepted + refusée + + + Debit + Débit + + + Total debit + Débit total + + + Total credit + Crédit total + + + Transaction fee + Frais de transaction + + + Net amount + Montant net + + + Message + Message + + + Comment + Commentaire + + + Transaction ID + ID de la transaction + + + Output index + Index de sorties + + + Merchant + Marchand + + + 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. + Les pièces générées doivent mûrir pendant %1 blocs avant de pouvoir être dépensées. Lorsque ce bloc a été généré, il a été diffusé sur le réseau pour être ajouté à la chaîne de blocs. Si son intégration à la chaîne échoue, son état sera modifié en « refusée » et il ne sera pas possible de le dépenser. Cela peut arriver occasionnellement si un autre nœud génère un bloc à quelques secondes du vôtre. + + + Debug information + Informations de débogage + + + Transaction + Transaction + + + Inputs + Entrées + + + Amount + Montant + + + true + vrai + + + false + faux + + TransactionDescDialog This pane shows a detailed description of the transaction Ce panneau affiche une description détaillée de la transaction - + + Details for %1 + Détails de %1 + + TransactionTableModel + + Date + Date + + + Type + Type + Label Étiquette + + Open for %n more block(s) + Ouvert pour %n bloc de plusOuvert pour %n blocs de plus + + + Open until %1 + Ouvert jusqu'à %1 + + + Offline + Hors ligne + + + Unconfirmed + Non confirmée + + + Abandoned + Abandonnée + + + Confirming (%1 of %2 recommended confirmations) + Confirmation (%1 sur %2 confirmations recommandées) + + + Confirmed (%1 confirmations) + Confirmée (%1 confirmations) + + + Conflicted + En conflit + + + Immature (%1 confirmations, will be available after %2) + Immature (%1 confirmations, sera disponible après %2) + + + This block was not received by any other nodes and will probably not be accepted! + Ce bloc n’a été reçu par aucun autre nœud et ne sera probablement pas accepté ! + + + Generated but not accepted + Générée mais refusée + + + Received with + Reçue avec + + + Received from + Reçue de + + + Sent to + Envoyée à + + + Payment to yourself + Paiement à vous-même + + + Mined + Miné + + + watch-only + juste-regarder + + + (n/a) + (n.d) + (no label) (aucune étiquette) - + + Transaction status. Hover over this field to show number of confirmations. + État de la transaction. Survoler ce champ avec la souris pour afficher le nombre de confirmations. + + + Date and time that the transaction was received. + Date et heure de réception de la transaction. + + + Type of transaction. + Type de transaction. + + + Whether or not a watch-only address is involved in this transaction. + Une adresse juste-regarder est-elle ou non impliquée dans cette transaction. + + + User-defined intent/purpose of the transaction. + Intention/but de la transaction défini par l'utilisateur. + + + Amount removed from or added to balance. + Le montant a été ajouté ou soustrait du solde. + + TransactionView + + All + Toutes + + + Today + Aujourd’hui + + + This week + Cette semaine + + + This month + Ce mois + + + Last month + Le mois dernier + + + This year + Cette année + + + Range... + Plage… + + + Received with + Reçue avec + + + Sent to + Envoyée à + + + To yourself + À vous-même + + + Mined + Miné + + + Other + Autres + + + Enter address or label to search + Saisir une adresse ou une étiquette à rechercher + + + Min amount + Montant min. + + + Abandon transaction + Abandonner la transaction + + + Copy address + Copier l’adresse + + + Copy label + Copier l’étiquette + + + Copy amount + Copier le montant + + + Copy transaction ID + Copier l'ID de la transaction + + + Copy raw transaction + Copier la transaction brute + + + Copy full transaction details + Copier tous les détails de la transaction + + + Edit label + Modifier l’étiquette + + + Show transaction details + Afficher les détails de la transaction + + + Export Transaction History + Exporter l'historique transactionnel + Comma separated file (*.csv) Valeurs séparées par des virgules (*.csv) + + Confirmed + Confirmée + + + Watch-only + Juste-regarder + + + Date + Date + + + Type + Type + Label Étiquette @@ -1884,11 +2836,35 @@ Address Adresse + + ID + ID + Exporting Failed - L'exportation a échoué + Échec d'exportation + + + There was an error trying to save the transaction history to %1. + Une erreur est survenue lors de l'enregistrement de l'historique transactionnel vers %1. + + + Exporting Successful + L'exportation est réussie + + + The transaction history was successfully saved to %1. + L'historique transactionnel a été enregistré avec succès vers %1. + + + Range: + Plage : + + + to + à - + UnitDisplayStatusBarControl @@ -1898,13 +2874,53 @@ WalletFrame - + + No wallet has been loaded. + Aucun porte-monnaie n'a été chargé. + + WalletModel - + + Send Coins + Envoyer des pièces + + WalletView - + + &Export + &Exporter + + + Export the data in the current tab to a file + Exporter les données de l'onglet actuel vers un fichier + + + Backup Wallet + Sauvegarder le porte-monnaie + + + Wallet Data (*.dat) + Données du porte-monnaie (*.dat) + + + Backup Failed + Échec de la sauvegarde + + + There was an error trying to save the wallet data to %1. + Une erreur est survenue lors de l'enregistrement des données du porte-monnaie vers %1. + + + Backup Successful + La sauvegarde est réussie + + + The wallet data was successfully saved to %1. + Les données du porte-monnaie ont été enregistrées avec succès vers %1 + + bitcoin-core @@ -2077,7 +3093,7 @@ Attempt to recover private keys from a corrupt wallet on startup - Tenter de récupérer les clefs privées d'un porte-monnaie corrompu lors du démarrage + Tenter de récupérer les clés privées d'un porte-monnaie corrompu lors du démarrage Block creation options: @@ -2259,6 +3275,10 @@ Specify wallet file (within data directory) Spécifiez le fichier de porte-monnaie (dans le répertoire de données) + + Starting network threads... + Démarrage des processus réseau... + The source code is available from %s. Le code source est disponible sur %s. @@ -2285,7 +3305,7 @@ Verifying blocks... - Vérification des blocs... + Vérification des blocs... Verifying wallet... @@ -2357,7 +3377,7 @@ Set maximum size of high-priority/low-fee transactions in bytes (default: %d) - Définir la taille maximale en octets des transactions prioritaires/à frais modiques (par défaut : %d) + Définir la taille maximale en octets des transactions à priorité élevée et frais modiques (par défaut : %d) The transaction amount is too small to send after the fee has been deducted @@ -2369,7 +3389,7 @@ Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start - Utiliser une génération de clef hiérarchique déterministe (HD) après BIP32. N'a d'effet que lors de la création/premier lancement du porte-monnaie + Utiliser une génération de clé hiérarchique déterministe (HD) après BIP32. N'a d'effet que lors de la création ou du lancement intitial du porte-monnaie Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway @@ -2401,7 +3421,7 @@ Imports blocks from external blk000??.dat file on startup - Importe des blocs depuis un fichier blk000??.dat externe lors du démarrage + Importe des blocs à partir d'un fichier blk000??.dat externe lors du démarrage Information @@ -2545,11 +3565,11 @@ -maxtxfee is set very high! Fees this large could be paid on a single transaction. - -maxtxfee est défini très haut ! Des frais aussi élevés pourraient être payés en une seule transaction. + La valeur -maxtxfee est très élevée ! Des frais aussi élevés pourraient être payés en une seule transaction. -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. - -paytxfee est réglé sur un montant très élevé ! Il s'agit des frais de transaction que vous payerez si vous envoyez une transaction. + La valeur -paytxfee est très élevée ! Il s'agit des frais de transaction que vous payerez si vous envoyez une transaction. Do not keep transactions in the mempool longer than <n> hours (default: %u) @@ -2669,7 +3689,7 @@ Set key pool size to <n> (default: %u) - Définir la taille de la réserve de clefs à <n> (par défaut : %u) + Définir la taille de la réserve de clés à <n> (par défaut : %u) Set the number of threads to service RPC calls (default: %d) diff --git a/src/qt/locale/bitcoin_it_IT.ts b/src/qt/locale/bitcoin_it_IT.ts index 10216a71f..c36ae2e48 100644 --- a/src/qt/locale/bitcoin_it_IT.ts +++ b/src/qt/locale/bitcoin_it_IT.ts @@ -59,9 +59,17 @@ Repeat new passphrase Ripeti nuova passphrase - + + Warning: The Caps Lock key is on! + Attenzione: Il tasto blocco delle maiuscole è attivo! + + BanTableModel + + IP/Netmask + IP/Netmask + Banned Until bannato fino diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts index 3fc93b7e2..399322d45 100644 --- a/src/qt/locale/bitcoin_ko_KR.ts +++ b/src/qt/locale/bitcoin_ko_KR.ts @@ -41,9 +41,21 @@ &Delete 삭제(&D) + + C&hoose + 선택 (&H) + + + &Edit + 편집 (&E) + AddressTableModel + + Address + 주소 + AskPassphraseDialog @@ -466,6 +478,10 @@ Priority 우선순위 + + Copy address + 주소 복사 + EditAddressDialog @@ -1380,6 +1396,10 @@ &Save Image... 이미지 저장(&S)... + + Address + 주소 + RecentRequestsTableModel @@ -1744,6 +1764,14 @@ TransactionView + + Copy address + 주소 복사 + + + Address + 주소 + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_ku_IQ.ts b/src/qt/locale/bitcoin_ku_IQ.ts index 9e52770aa..80fa68289 100644 --- a/src/qt/locale/bitcoin_ku_IQ.ts +++ b/src/qt/locale/bitcoin_ku_IQ.ts @@ -28,6 +28,10 @@ AddressTableModel + + Address + ناوونیشان + AskPassphraseDialog @@ -92,6 +96,22 @@ Priority لەپێشی + + high + بەرز + + + low + نزم + + + yes + بەڵێ + + + no + نەخێر + EditAddressDialog @@ -160,14 +180,30 @@ &Information &زانیاری + + General + گشتی + + + Network + تۆڕ + Name ناو + + Sent + نێدرا + Version وەشان + + Services + خزمەتگوزاریەکان + &Open &کردنەوە @@ -180,6 +216,34 @@ Totals گشتییەکان + + In: + لە ناو + + + Out: + لەدەرەوە + + + 1 &hour + 1&سات + + + 1 &day + 1&ڕۆژ + + + 1 &week + 1&هەفتە + + + 1 &year + 1&ساڵ + + + never + هەرگیز + Yes بەڵێ @@ -214,6 +278,10 @@ ReceiveRequestDialog + + Address + ناوونیشان + RecentRequestsTableModel @@ -270,6 +338,10 @@ TransactionView + + Address + ناوونیشان + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts index 57c336c85..deb6c37c7 100644 --- a/src/qt/locale/bitcoin_pl.ts +++ b/src/qt/locale/bitcoin_pl.ts @@ -41,9 +41,57 @@ &Delete &Usuń + + Sending addresses + Adresy wysyłania + + + Receiving addresses + Adresy odbioru + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + Tutaj znajdują się adresy Bitcoin na które wysyłasz płatności. Zawsze sprawdzaj ilość i adres odbiorcy przed wysyłką monet. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + To są twoje adresy Bitcoin do odbierania płatności. Zaleca się używanie nowych adresów odbiorczych dla każdej transakcji. + + + &Copy Address + &Kopiuj adres + + + Copy &Label + Kopiuj &Etykietę + + + &Edit + &Edytuj + + + Export Address List + Eksportuj listę adresów + + + Comma separated file (*.csv) + Plik *.CSV (dane rozdzielane przecinkami) + + + Exporting Failed + Eksportowanie nie powiodło się + AddressTableModel + + Label + Etykieta + + + Address + Adres + AskPassphraseDialog @@ -63,6 +111,50 @@ Repeat new passphrase Powtórz nowe hasło + + Encrypt wallet + Zaszyfruj portfel + + + Unlock wallet + Odblokuj portfel + + + Decrypt wallet + Odszyfruj portfel + + + Change passphrase + Zmień hasło + + + Enter the old passphrase and new passphrase to the wallet. + Podaj stare i nowe hasło do portfela. + + + Confirm wallet encryption + Potwierdź szyfrowanie portfela + + + Wallet encrypted + Portfel zaszyfrowany + + + Wallet encryption failed + Szyfrowanie portfela nie powiodło się + + + Wallet unlock failed + Odblokowanie portfela nie powiodło się + + + The passphrase entered for the wallet decryption was incorrect. + Wprowadzone hasło do odszyfrowania portfela jest niepoprawne. + + + Wallet decryption failed + Odszyfrowanie portfela nie powiodło się + BanTableModel @@ -466,6 +558,86 @@ Priority Priorytet + + Copy address + Kopiuj adres + + + Copy label + Kopiuj etykietę + + + Copy amount + Kopiuj kwotę + + + Copy transaction ID + Skopiuj ID transakcji + + + Lock unspent + Zablokuj niewydane + + + Unlock unspent + Odblokuj niewydane + + + Copy quantity + Skopiuj ilość + + + Copy fee + Skopiuj prowizję + + + Copy after fee + Skopiuj ilość po opłacie + + + highest + najwyższy + + + higher + wyższy + + + high + wysoki + + + medium-high + średnio wysoki + + + medium + średni + + + low-medium + średnio niski + + + low + niski + + + lower + niższy + + + lowest + najniższy + + + yes + tak + + + no + nie + EditAddressDialog @@ -1361,7 +1533,15 @@ Remove Usuń - + + Copy label + Kopiuj etykietę + + + Copy amount + Kopiuj kwotę + + ReceiveRequestDialog @@ -1380,9 +1560,21 @@ &Save Image... &Zapisz obraz... + + Address + Adres + + + Label + Etykieta + RecentRequestsTableModel + + Label + Etykieta + SendCoinsDialog @@ -1534,6 +1726,22 @@ S&end Wy&syłka + + Copy quantity + Skopiuj ilość + + + Copy amount + Kopiuj kwotę + + + Copy fee + Skopiuj prowizję + + + Copy after fee + Skopiuj ilość po opłacie + SendCoinsEntry @@ -1742,9 +1950,45 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw TransactionTableModel + + Label + Etykieta + TransactionView + + Copy address + Kopiuj adres + + + Copy label + Kopiuj etykietę + + + Copy amount + Kopiuj kwotę + + + Copy transaction ID + Skopiuj ID transakcji + + + Comma separated file (*.csv) + Plik *.CSV (dane rozdzielane przecinkami) + + + Label + Etykieta + + + Address + Adres + + + Exporting Failed + Eksportowanie nie powiodło się + UnitDisplayStatusBarControl @@ -1796,6 +2040,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) Prune: ostatnia synchronizacja portfela jest za danymi. Muszisz -reindexować (pobrać cały ciąg bloków ponownie w przypadku przyciętego węzła) + + Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) + Zredukuj wymaganą ilość miejsca na dysku poprzez usuwanie starych bloków. Ten tryb jest niekompatybilny z -txindex oraz -rescan. Ostrzeżenie: Wycofanie tego ustawienia wymaga ponownego pobrania całego łańcucha bloków. (domyślnie: 0 = wyłącz usuwanie bloków, >%u = docelowy rozmiar w MiB jaki wykorzystać na pliki z blokami) + + + Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. + Ponowne skanowanie nie jest możliwe w trybie przycinania. Będzie trzeba użyć -reindex, co pobierze ponownie cały łańcuch bloków. + Error: A fatal internal error occurred, see debug.log for details Błąd: Wystąpił fatalny błąd wewnętrzny, sprawdź szczegóły w debug.log @@ -1832,6 +2084,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw -fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available. -fallbackfee ma ustawioną bardzo dużą wartość! Jest to prowizja za transakcje, którą możesz zapłacić gdy oszacowanie opłaty jest niemożliwe. + + A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s) + Stawka prowizji (w %s/kB), która będzie użyta, gdy oszacowane dane o prowizjach nie będą wystarczające (domyślnie: %s) + + + Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d) + Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d) + Bind to given address and always listen on it. Use [host]:port notation for IPv6 Skojarz z podanym adresem i nasłuchuj na nim. Użyj formatu [host]:port dla IPv6 diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts index 2dbd28dc6..aeaf99f50 100644 --- a/src/qt/locale/bitcoin_pt_BR.ts +++ b/src/qt/locale/bitcoin_pt_BR.ts @@ -41,10 +41,78 @@ &Delete &Excluir - + + Choose the address to send coins to + Escoha o endereço para enviar moedas + + + Choose the address to receive coins with + Escolha o enereço para receber moedas + + + C&hoose + Escol&ha + + + Sending addresses + Endereços de envio + + + Receiving addresses + Endereços de recebimento + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + 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. + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + Estes são os seus endereços para receber pagamentos. É recomendado usar um novo para cada transação. + + + &Copy Address + &Copiar endereço + + + Copy &Label + Copiar rótu&lo + + + &Edit + &Editar + + + Export Address List + Exportar lista de endereços + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + Exporting Failed + Falha na exportação + + + There was an error trying to save the address list to %1. Please try again. + Erro ao salvar a lista de endereço para %1. Tente novamente. + + AddressTableModel - + + Label + Rótuo + + + Address + Endereço + + + (no label) + (sem rótuo) + + AskPassphraseDialog @@ -63,7 +131,91 @@ Repeat new passphrase Repita a nova frase de segurança - + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Insira a nova senha para a carteira.<br/>Favor usar uma senha com <b>dez ou mais caracteres aleatórios</b>, ou <b>oito ou mais palavras</b>. + + + Encrypt wallet + Criptografar carteira + + + This operation needs your wallet passphrase to unlock the wallet. + Esta operação precisa da sua senha para desbloquear a carteira. + + + Unlock wallet + Desbloquear carteira + + + This operation needs your wallet passphrase to decrypt the wallet. + Esta operação precisa da sua senha para descriptografar a carteira + + + Decrypt wallet + Descriptografar carteira + + + Change passphrase + Alterar senha + + + Enter the old passphrase and new passphrase to the wallet. + Insira a senha antiga e a nova para a carteira. + + + Confirm wallet encryption + Confirmar criptografia da carteira + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + Aviso: Se você criptografar sua carteira e perder sua senha, você vai <b>PERDER TODOS OS SEUS BITCOINS</b>! + + + Are you sure you wish to encrypt your wallet? + Tem certeza que deseja criptografar a carteira? + + + Wallet encrypted + Carteira criptografada + + + 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. + IMPORTANTE: Qualquer backup prévio que você tenha feito da sua carteira deve ser substituído pelo novo e encriptado arquivo gerado. Por razões de segurança, qualquer backup do arquivo não criptografado se tornará inútil assim que você começar a usar uma nova carteira criptografada. + + + Wallet encryption failed + Falha ao criptografar carteira + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Falha na criptografia devido a um erro inerno. Sua carteira não foi criptografada. + + + The supplied passphrases do not match. + As senhas não conferem. + + + Wallet unlock failed + Falha ao desbloquear carteira + + + The passphrase entered for the wallet decryption was incorrect. + A senha inserida para descriptografar a carteira está incorreta. + + + Wallet decryption failed + Falha ao descriptografar a carteira + + + Wallet passphrase was successfully changed. + A senha da carteira foi alterada com êxito. + + + Warning: The Caps Lock key is on! + Aviso: Tecla Caps Lock ativa! + + BanTableModel @@ -179,7 +331,7 @@ &Debug window - Janela de &Depuração + Janela de &depuração Open debugging and diagnostic console @@ -466,7 +618,151 @@ Priority Prioridade - + + Copy address + Copiar endereço + + + Copy label + Copiar rótulo + + + Copy amount + Copiar quantia + + + Copy transaction ID + Copiar ID da transação + + + Lock unspent + Boquear saída + + + Unlock unspent + Desboquear saída + + + Copy quantity + Copiar quantia + + + Copy fee + Copiar taxa + + + Copy after fee + Copiar pós taxa + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridade + + + Copy dust + Copiar poeira + + + Copy change + Copiar troco + + + highest + mega alta + + + higher + super alta + + + high + alta + + + medium-high + média alta + + + medium + média + + + low-medium + média baixa + + + low + baixa + + + lower + super baixa + + + lowest + mega baixa + + + (%1 locked) + (%1 bloqueada) + + + none + nenhum + + + yes + sim + + + no + não + + + This label turns red if the transaction size is greater than 1000 bytes. + Este texto fica vermeho se o tamanho da transação for maior que 1 KiB. + + + This means a fee of at least %1 per kB is required. + Isso quer dizer que uma taxa de pelo menos %1 per KiB será necessária. + + + Can vary +/- 1 byte per input. + Pode variar +/- 1 byte por entrada + + + Transactions with higher priority are more likely to get included into a block. + Transações de alta prioridade são mais propensas a serem incluídas em um bloco. + + + This label turns red if the priority is smaller than "medium". + Este texto fica vermelho se a prioridade é menor que "medio". + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + Este texto fica vermelho se qualquer destinatário receber uma quantidade menor que que o dust. + + + Can vary +/- %1 satoshi(s) per input. + Pode variar +/- %1 satoshi(s) por entrada + + + (no label) + (sem rótuo) + + + change from %1 (%2) + troco de %1 (%2) + + + (change) + (troco) + + EditAddressDialog @@ -489,7 +785,39 @@ &Address &Endereço - + + New receiving address + Novo endereço de recebimento + + + New sending address + Novo endereço de envio + + + Edit receiving address + Editar endereço de recebimento + + + Edit sending address + Editar endereço de envio + + + The entered address "%1" is not a valid Bitcoin address. + O endereço digitado "%1" não é um endereço válido. + + + The entered address "%1" is already in the address book. + O endereço digitado "%1" já se encontra no catálogo de endereços. + + + Could not unlock wallet. + Não foi possível desbloquear a carteira + + + New key generation failed. + Falha ao gerar chave + + FreespaceChecker @@ -629,7 +957,11 @@ Select payment request file Selecione o arquivo de cobrança - + + Select payment request file to open + Selecione o arquivo de cobrança para ser aberto + + OptionsDialog @@ -942,7 +1274,95 @@ PaymentServer - + + Payment request error + Erro no pedido de pagamento + + + Cannot start bitcoin: click-to-pay handler + Não foi possível iniciar bitcoin: manipulador click-to-pay + + + URI handling + Manipulação de URI + + + Payment request fetch URL is invalid: %1 + URL de cobrança é inválida: %1 + + + Invalid payment address %1 + Endereço de pagamento %1 inválido + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + URI não pode ser analisado! Isto pode ser causado por um endereço inválido ou parâmetros URI informados incorretamente. + + + Payment request file handling + Manipulação de arquivo de cobrança + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + Arquivo de pedido de pagamento não pode ser lido! Isto pode ser causado por uma requisição de pagamento inválida. + + + Payment request rejected + Pedido de pagamento rejeitado + + + Payment request network doesn't match client network. + Rede do pedido de pagamento não corresponde rede do cliente. + + + Payment request expired. + Pedido de pagamento expirado + + + Payment request is not initialized. + Pedido de pagamento não inicializado + + + Unverified payment requests to custom payment scripts are unsupported. + Pedidos de pagamento não verificados para scripts de pagamento personalizados não são suportados. + + + Invalid payment request. + Pedido de pagamento inválido + + + Requested payment amount of %1 is too small (considered dust). + Valor do pagamento solicitado de %1 é muito pequeno (Considerado poeira). + + + Refund from %1 + Reembolso de %1 + + + Payment request %1 is too large (%2 bytes, allowed %3 bytes). + Pedido de pagamento %1 é muito grande (%2 bytes, permitido %3 bytes). + + + Error communicating with %1: %2 + Erro na comunicação com %1: %2 + + + Payment request cannot be parsed! + Pedido de pagamento não pode ser analisado! + + + Bad response from server %1 + Erro na resposta do servidor: %1 + + + Network request error + Erro de solicitação de rede + + + Payment acknowledged + Pagamento reconhecido + + PeerTableModel @@ -999,7 +1419,23 @@ QRImageWidget - + + &Save Image... + &Savar imagem + + + &Copy Image + &Copiar imagem + + + Save QR Code + Salvar código QR + + + PNG Image (*.png) + Imagem PNG (*.png) + + RPCConsole @@ -1196,7 +1632,7 @@ Debug log file - Arquivo de log de Depuração + Arquivo de log de depuração Clear console @@ -1361,7 +1797,19 @@ Remove Remover - + + Copy label + Copiar rótulo + + + Copy message + Copiar mensagem + + + Copy amount + Copiar quantia + + ReceiveRequestDialog @@ -1380,43 +1828,107 @@ &Save Image... &Salvar Imagem... - - - RecentRequestsTableModel - - - SendCoinsDialog - Send Coins - Enviar moedas + Request payment to %1 + Pedido de pagamento para %1 - Coin Control Features - Opções de controle de moeda + Payment information + Informação do pagamento - Inputs... - Entradas... + URI + URI - automatically selected - automaticamente selecionado + Address + Endereço - Insufficient funds! - Saldo insuficiente! + Amount + Quantia - Quantity: - Quantidade: + Label + Rótuo - Bytes: - Bytes: + Message + Mensagem - Amount: - Quantia: + Resulting URI too long, try to reduce the text for label / message. + URI resultante muito longa. Tente reduzir o texto do rótulo ou da mensagem. + + + Error encoding URI into QR Code. + Erro ao codigicar o URI em código QR + + + + RecentRequestsTableModel + + Date + Data + + + Label + Rótuo + + + Message + Mensagem + + + (no label) + (sem rótuo) + + + (no message) + (sem mensagem) + + + (no amount requested) + (nenhuma quantia solicitada) + + + Requested + Solicitado + + + + SendCoinsDialog + + Send Coins + Enviar moedas + + + Coin Control Features + Opções de controle de moeda + + + Inputs... + Entradas... + + + automatically selected + automaticamente selecionado + + + Insufficient funds! + Saldo insuficiente! + + + Quantity: + Quantidade: + + + Bytes: + Bytes: + + + Amount: + Quantia: Priority: @@ -1534,7 +2046,119 @@ S&end Enviar - + + Copy quantity + Copiar quantia + + + Copy amount + Copiar quantia + + + Copy fee + Copiar taxa + + + Copy after fee + Copiar pós taxa + + + Copy bytes + Copiar bytes + + + Copy priority + Copiar prioridade + + + Copy dust + Copiar poeira + + + Copy change + Copiar troco + + + %1 to %2 + %1 a %2 + + + Are you sure you want to send? + Tem certeza que deseja enviar? + + + added as transaction fee + adicionado como taxa da transação + + + Total Amount %1 + Quantia tota %1 + + + or + ou + + + Confirm send coins + Confirme o envio de moedas + + + The recipient address is not valid. Please recheck. + Endereço de envio inváido. Favor checar. + + + The amount to pay must be larger than 0. + A quantia à pagar deve ser maior que 0 + + + The amount exceeds your balance. + A quantia excede o seu saldo + + + The total exceeds your balance when the %1 transaction fee is included. + O total excede o seu saldo quando a taxa da transação %1 é incluída + + + Duplicate address found: addresses should only be used once each. + Endereço duplicado encontrado: Endereços devem ser usados somente uma vez cada. + + + Transaction creation failed! + Falha na criação da transação + + + The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. + A transação foi rejeitada! Isso pode acontecer se algumas moedas na sua carteira já foram gastas em outro local, por exemplo se você tiver uma cópia da carteira e as moedas tiverem sido gastas na cópia mas não marcados como gastas aqui ainda. + + + A fee higher than %1 is considered an absurdly high fee. + Uma taxa maior que %1 é considerada uma taxa absurdamente alta. + + + Payment request expired. + Pedido de pagamento expirado + + + Pay only the required fee of %1 + Pagar somente a taxa requerida de %1 + + + Estimated to begin confirmation within %n block(s). + Estimado a começar confirmação em %n bloco(s).Estimado começar confirmação em %n bloco(s). + + + Warning: Invalid Bitcoin address + Aviso: Endereço inválido + + + Warning: Unknown change address + Aviso: Endereço de troco inválido + + + (no label) + (sem rótuo) + + SendCoinsEntry @@ -1613,10 +2237,18 @@ Memo: Memorizar: - + + Enter a label for this address to add it to your address book + Digite um rótulo para este endereço para adicioná-lo ao catálogo de endereços + + SendConfirmationDialog - + + Yes + Sim + + ShutdownWindow @@ -1710,7 +2342,59 @@ Reset all verify message fields Limpar todos os campos de assinatura da mensagem - + + Click "Sign Message" to generate signature + Clique em "Assinar mensagem" para gerar a assinatura + + + The entered address is invalid. + O endereço digitado é inválido + + + Please check the address and try again. + Favor checar o endereço e tente novamente + + + The entered address does not refer to a key. + O endereço fornecido não se refere a uma chave. + + + Wallet unlock was cancelled. + O desbloqueio da carteira foi cancelado + + + Private key for the entered address is not available. + A chave privada do endereço inserido não está disponível + + + Message signing failed. + Falha ao assinar mensagem + + + Message signed. + Mensagem assinada + + + The signature could not be decoded. + A assinatura não pode ser descodificada + + + Please check the signature and try again. + Favor checar a assinatura e tente novamente + + + The signature did not match the message digest. + A assinatura não corresponde a mensagem + + + Message verification failed. + Falha na verificação da mensagem + + + Message verified. + Mensagem verificada + + SplashScreen @@ -1727,20 +2411,456 @@ TransactionDesc - + + Open for %n more block(s) + Aberto para mais %n bloco(s)Aberto para mais %n bloco(s) + + + Open until %1 + Aberto até %1 + + + conflicted with a transaction with %1 confirmations + conflitado com uma transação com %1 confirmações + + + %1/offline + %1/offline + + + 0/unconfirmed, %1 + 0/não confirmado, %1 + + + in memory pool + na memória + + + not in memory pool + não na memóra + + + abandoned + abandonado + + + %1/unconfirmed + %1/não confirmado + + + %1 confirmations + %1 confirmações + + + Status + Status + + + , has not been successfully broadcast yet + , ainda não foi propagada na rede com êxito. + + + , broadcast through %n node(s) + , propagada por %n nó(s), propagada por %n nó(s) + + + Date + Data + + + Source + Fonte + + + Generated + Gerado + + + From + De + + + unknown + desconhecido + + + To + Para + + + own address + próprio endereço + + + watch-only + monitorado + + + label + rótulo + + + Credit + Crédito + + + matures in %n more block(s) + amadurece em mais %n bloco(s)amadurece em mais %n bloco(s) + + + not accepted + não aceito + + + Debit + Débito + + + Total debit + Débito total + + + Total credit + Crédito total + + + Transaction fee + Taxa da transação + + + Net amount + Valor líquido + + + Message + Mensagem + + + Comment + Comentário + + + Transaction ID + ID da transação + + + Output index + Index da saída + + + Merchant + Mercador + + + 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. + Moedas recém minerados precisam aguardar %1 blocos antes de serem gastos. Quando o bloco foi gerado, ele foi disseminado pela rede para ser adicionado à blockchain. Se ele falhar em ser inserido na cadeia, seu estado será modificado para "não aceito" e ele não poderá ser gasto. Isso pode acontecer eventualmente quando blocos são gerados quase que simultaneamente. + + + Debug information + Depurar informação + + + Transaction + Transação + + + Inputs + Entradas + + + Amount + Quantia + + + true + verdadeiro + + + false + falso + + TransactionDescDialog This pane shows a detailed description of the transaction Este painel mostra uma descrição detalhada da transação - + + Details for %1 + Detalhes para %1 + + TransactionTableModel - + + Date + Data + + + Type + Tipo + + + Label + Rótuo + + + Open for %n more block(s) + Aberto por mais %n bloco(s)Aberto por mais %n bloco(s) + + + Open until %1 + Aberto até %1 + + + Offline + Offline + + + Unconfirmed + Não confirmado + + + Abandoned + Abandonado + + + Confirming (%1 of %2 recommended confirmations) + Confirmando (%1 de %2 confirmações recomendadas) + + + Confirmed (%1 confirmations) + Confirmado (%1 confirmações) + + + Conflicted + Conflitado + + + Immature (%1 confirmations, will be available after %2) + Recém-criado (%1 confirmações, disponível somente após %2) + + + This block was not received by any other nodes and will probably not be accepted! + Este bloco não foi recebido por nenhum outro participante da rede e provavelmente não será aceito! + + + Generated but not accepted + Gerado mas não aceito + + + Received with + Recebido em + + + Received from + Recebido de + + + Sent to + Enviado para + + + Payment to yourself + Pagamento para você mesmo + + + Mined + Minerado + + + watch-only + monitorado + + + (n/a) + (n/a) + + + (no label) + (sem rótuo) + + + Transaction status. Hover over this field to show number of confirmations. + Status da transação. Passe o mouse sobre este campo para mostrar o número de confirmações. + + + Date and time that the transaction was received. + Data e hora em que a transação foi recebida. + + + Type of transaction. + Tipo de transação + + + Whether or not a watch-only address is involved in this transaction. + Mostrar ou não endereços monitorados na lista de transações. + + + User-defined intent/purpose of the transaction. + Intenção/Propósito definido pelo usuário para a transação + + + Amount removed from or added to balance. + Quantidade debitada ou creditada ao saldo. + + TransactionView - + + All + Todos + + + Today + Hoje + + + This week + Essa semana + + + This month + Esse mês + + + Last month + Último mês + + + This year + Este ano + + + Range... + Intervalo... + + + Received with + Recebido em + + + Sent to + Enviado para + + + To yourself + Para você mesmo + + + Mined + Minerado + + + Other + Outro + + + Enter address or label to search + Procure um endereço ou rótulo + + + Min amount + Quantia mínima + + + Abandon transaction + Transação abandonada + + + Copy address + Copiar endereço + + + Copy label + Copiar rótulo + + + Copy amount + Copiar quantia + + + Copy transaction ID + Copiar ID da transação + + + Copy raw transaction + Copiar o raw da transação + + + Copy full transaction details + Copiar dados completos da transação + + + Edit label + Editar rótulo + + + Show transaction details + Mostrar detalhes da transação + + + Export Transaction History + Exportar histórico de transações + + + Comma separated file (*.csv) + Comma separated file (*.csv) + + + Confirmed + Confirmado + + + Watch-only + Monitorado + + + Date + Data + + + Type + Tipo + + + Label + Rótuo + + + Address + Endereço + + + ID + ID + + + Exporting Failed + Falha na exportação + + + There was an error trying to save the transaction history to %1. + Ocorreu um erro ao tentar salvar o histórico de transações em %1. + + + Exporting Successful + Exportação feita com êxito + + + The transaction history was successfully saved to %1. + O histórico de transação foi gravado com êxito em %1. + + + Range: + Intervalo: + + + to + para + + UnitDisplayStatusBarControl @@ -1750,13 +2870,53 @@ WalletFrame - + + No wallet has been loaded. + Nenhuma carteira carregada + + WalletModel - + + Send Coins + Enviar moedas + + WalletView - + + &Export + &Exportar + + + Export the data in the current tab to a file + Exportar os dados da guia atual para um arquivo + + + Backup Wallet + Backup da carteira + + + Wallet Data (*.dat) + Dados da carteira (*.dat) + + + Backup Failed + Falha no backup + + + There was an error trying to save the wallet data to %1. + Ocorreu um erro ao tentar salvar os dados da carteira em %1. + + + Backup Successful + Êxito no backup + + + The wallet data was successfully saved to %1. + Os dados da carteira foram salvos com êxito em %1. + + bitcoin-core @@ -1793,7 +2953,7 @@ Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files) - Reduza os requerimentos de armazenamento de dados (cortando) deletando blocos mais antigos. Esse modo é incompatível com -txindex e -rescan. Cuidado: Reverter essa configuração requer um novo download de toda a blockchain. (Padrão: 0 = desabilita o corte de blocos, >%u = tamanho alvo em MiB para o uso de blocos cortados) + Reduza o armazenamento de dados apagando os blocos mais antigos. Esse modo é incompatível com -txindex e -rescan. Cuidado: Reverter essa configuração requer um novo download de toda a blockchain. (Padrão: 0 = desabilitado, >%u = tamanho em MiB para o uso de blocos cortados) Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. @@ -1855,6 +3015,10 @@ Distributed under the MIT software license, see the accompanying file COPYING or <http://www.opensource.org/licenses/mit-license.php>. Distribuido sob a licença MIT software license. Veja os termos em <http://www.opensource.org/licenses/mit-license.php>. + + Equivalent bytes per sigop in transactions for relay and mining (default: %u) + Número mínimo de bytes por assinatura em transações que transmitimos e mineramos (default: %u) + Error loading %s: You can't enable HD on a already existing non-HD wallet Erro ao carregar %s. Não é permitido habilitar HD em carteiras não-HD pre existentes. @@ -2099,6 +3263,14 @@ Prune mode is incompatible with -txindex. O modo prune é incompatível com -txindex. + + Rebuild chain state and block index from the blk*.dat files on disk + Reconstruir índice de cadeia de bloco a partir dos arquivos blk*.dat no disco + + + Rebuild chain state from the currently indexed blocks + Reconstruir estado a partir dos blocos indexados + Rewinding blocks... Reanalizando blocos... @@ -2119,6 +3291,10 @@ Specify wallet file (within data directory) Especifique o arquivo da carteira (dentro do diretório de dados) + + Starting network threads... + Iniciando análise da rede... + The source code is available from %s. O código fonte está disponível pelo %s @@ -2199,13 +3375,17 @@ Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s) Comissões (em %s/kB) menores serão consideradas como zero para relaying, mineração e criação de transação (padrão %s) + + Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d) + Força a retransmissão de transações de pares da lista branca, mesmo quando violam a política local de retransmissão (default: %d) + If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) Se paytxfee não estiver definida, incluir comissão suficiente para que as transações comecem a ter confirmações em média dentro de N blocos (padrão %u) Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) - Valor inválido para -maxtxfee = <valor>: '%s'( precisa ser pelo menos a comissão mínima de %s para prevenir travamento de transações) + Valor inválido para -maxtxfee=<valor>: '%s' (precisa ser pelo menos a taxa mínima de %s para prevenir que a transação nunca seja confirmada) Maximum size of data in data carrier transactions we relay and mine (default: %u) @@ -2231,6 +3411,10 @@ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard. Esse produto inclui software desenvolvido pelo Open SSL Project para uso na OpenSSL Toolkit <https://www.openssl.org> e software criptográfico escrito por Eric Young e software UPnP escrito por Thomas Bernard. + + Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start + Usar carteira HD. Somente tem efeito na criação de uma nova carteira + Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway Peers permitidos não podem ser banidos do DoS e suas transações sempre são transmitidas, até mesmo se eles já estão no pool de memória, útil, por exemplo, para um gateway diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts index cbecf9058..e4c5bef16 100644 --- a/src/qt/locale/bitcoin_pt_PT.ts +++ b/src/qt/locale/bitcoin_pt_PT.ts @@ -41,6 +41,14 @@ &Delete &Eliminar + + Choose the address to send coins to + Escolhe qual o endereço para o qual enviar moedas + + + Choose the address to receive coins with + Escolhe qual o endereço para receber moedas + AddressTableModel diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts index ee0568ed5..7e46f251d 100644 --- a/src/qt/locale/bitcoin_sk.ts +++ b/src/qt/locale/bitcoin_sk.ts @@ -44,7 +44,11 @@ AddressTableModel - + + (no label) + (bez popisu) + + AskPassphraseDialog @@ -466,6 +470,10 @@ Priority Priorita + + (no label) + (bez popisu) + EditAddressDialog @@ -1384,6 +1392,10 @@ RecentRequestsTableModel + + (no label) + (bez popisu) + SendCoinsDialog @@ -1535,7 +1547,15 @@ S&end &Odoslať - + + or + alebo + + + (no label) + (bez popisu) + + SendCoinsEntry @@ -1734,6 +1754,10 @@ TransactionTableModel + + (no label) + (bez popisu) + TransactionView diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts index 5b122f76c..7e30b263a 100644 --- a/src/qt/locale/bitcoin_sv.ts +++ b/src/qt/locale/bitcoin_sv.ts @@ -73,10 +73,47 @@ &Copy Address &Kopiera adress - + + Copy &Label + Kopiera &etikett + + + &Edit + &Redigera + + + Export Address List + Exportera adresslista + + + Comma separated file (*.csv) + Kommaseparerad fil (*.csv) + + + Exporting Failed + Export misslyckades + + + There was an error trying to save the address list to %1. Please try again. + Det inträffade ett fel när adresslistan skulle sparas till %1. +Var vänlig och försök igen. + + AddressTableModel - + + Label + Etikett + + + Address + Adress + + + (no label) + (Ingen etikett) + + AskPassphraseDialog @@ -95,7 +132,95 @@ Repeat new passphrase Upprepa nytt lösenord - + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + Ange plånbokens nya lösenord. <br/> Använd ett lösenord på <b>tio eller fler slumpmässiga tecken,</b> eller <b>åtta eller fler ord.</b>. + + + Encrypt wallet + Kryptera plånbok + + + This operation needs your wallet passphrase to unlock the wallet. + Denna operation behöver din plånboks lösenord för att låsa upp plånboken. + + + Unlock wallet + Lås upp plånbok + + + This operation needs your wallet passphrase to decrypt the wallet. + Denna operation behöver din plånboks lösenord för att dekryptera plånboken. + + + Decrypt wallet + Dekryptera plånbok + + + Change passphrase + Ändra lösenord + + + Enter the old passphrase and new passphrase to the wallet. + Ge det gamla lösenordet och det nya lösenordet för plånboken. + + + Confirm wallet encryption + Bekräfta kryptering av plånbok + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + VARNING: Om du krypterar din plånbok och glömmer ditt lösenord, kommer du att <b>FÖRLORA ALLA DINA BITCOIN</b>! + + + Are you sure you wish to encrypt your wallet? + Är du säker på att du vill kryptera din plånbok? + + + Wallet encrypted + Plånbok krypterad + + + %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + %1 kommer nu att stänga ner för att färdigställa krypteringen. Tänk på att en krypterad plånbok inte skyddar mot stöld om din dator är infekterad med en keylogger. + + + 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. + VIKTIGT: Alla tidigare säkerhetskopior du har gjort av plånboksfilen ska ersättas med den nya genererade, krypterade plånboksfilen. Av säkerhetsskäl kommer tidigare säkerhetskopior av den okrypterade plånboksfilen blir oanvändbara när du börjar använda en ny, krypterad plånbok. + + + Wallet encryption failed + Kryptering av plånbok misslyckades + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + Kryptering av plånbok misslyckades på grund av ett internt fel. Din plånbok blev inte krypterad. + + + The supplied passphrases do not match. + De angivna lösenorden överensstämmer inte. + + + Wallet unlock failed + Misslyckades låsa upp plånboken + + + The passphrase entered for the wallet decryption was incorrect. + Lösenordet för dekryptering av plånboken var felaktig. + + + Wallet decryption failed + Dekryptering av plånbok misslyckades + + + Wallet passphrase was successfully changed. + Plånbokens lösenord har ändrats. + + + Warning: The Caps Lock key is on! + Varning: Caps Lock är påslaget! + + BanTableModel @@ -498,6 +623,22 @@ Priority Prioritet + + Copy address + Kopiera adress + + + Copy label + Kopiera etikett + + + Copy amount + Kopiera belopp + + + (no label) + (Ingen etikett) + EditAddressDialog @@ -1393,7 +1534,15 @@ Remove Ta bort - + + Copy label + Kopiera etikett + + + Copy amount + Kopiera belopp + + ReceiveRequestDialog @@ -1412,9 +1561,25 @@ &Save Image... &Spara Bild... + + Address + Adress + + + Label + Etikett + RecentRequestsTableModel + + Label + Etikett + + + (no label) + (Ingen etikett) + SendCoinsDialog @@ -1566,7 +1731,15 @@ S&end &Skicka - + + Copy amount + Kopiera belopp + + + (no label) + (Ingen etikett) + + SendCoinsEntry @@ -1773,9 +1946,45 @@ TransactionTableModel + + Label + Etikett + + + (no label) + (Ingen etikett) + TransactionView + + Copy address + Kopiera adress + + + Copy label + Kopiera etikett + + + Copy amount + Kopiera belopp + + + Comma separated file (*.csv) + Kommaseparerad fil (*.csv) + + + Label + Etikett + + + Address + Adress + + + Exporting Failed + Export misslyckades + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_ta.ts b/src/qt/locale/bitcoin_ta.ts index 699ded2c6..1ce2c4df8 100644 --- a/src/qt/locale/bitcoin_ta.ts +++ b/src/qt/locale/bitcoin_ta.ts @@ -25,9 +25,21 @@ &Delete &அழி + + Sending addresses + முகவரிகள் அனுப்பப்படுகின்றன + + + Receiving addresses + முகவரிகள் பெறப்படுகின்றன + AddressTableModel + + Address + முகவரி + AskPassphraseDialog @@ -558,6 +570,10 @@ &Save Image... &படத்தை சேமி... + + Address + முகவரி + RecentRequestsTableModel @@ -678,6 +694,10 @@ TransactionView + + Address + முகவரி + UnitDisplayStatusBarControl diff --git a/src/qt/locale/bitcoin_vi_VN.ts b/src/qt/locale/bitcoin_vi_VN.ts index 5774f5b9b..fdfc92117 100644 --- a/src/qt/locale/bitcoin_vi_VN.ts +++ b/src/qt/locale/bitcoin_vi_VN.ts @@ -619,6 +619,10 @@ QRImageWidget + + &Save Image... + $Lưu hình ảnh... + RPCConsole @@ -646,6 +650,58 @@ User Agent User Agent + + 1 &hour + 1&giờ + + + 1 &day + 1&ngày + + + 1 &week + 1&tuần + + + 1 &year + 1&năm + + + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. + Sử dụng phím lên và xuống để di chuyển lịch sử, và <b>Ctrl-L</b> để xóa màn hình + + + Type <b>help</b> for an overview of available commands. + Gõ <b>help</b> để xem nhưng câu lệnh có sẵn + + + %1 B + %1 B + + + %1 KB + %1 KB + + + %1 MB + %1 MB + + + %1 GB + %1 GB + + + never + không bao giờ + + + Yes + Đồng ý + + + No + Không + ReceiveCoinsDialog @@ -653,19 +709,119 @@ &Amount: Lượng: + + &Label: + &Nhãn + + + &Message: + &Tin nhắn: + + + Use this form to request payments. All fields are <b>optional</b>. + Sử dụng form này để yêu cầu thanh toán. Tất cả các trường <b>không bắt buộc<b> + + + Clear all fields of the form. + Xóa tất cả các trường trong biểu mẫu + + + Clear + Xóa + + + Requested payments history + Lịch sử yêu cầu thanh toán + + + &Request payment + &Yêu cầu thanh toán + + + Show + Hiển thị + + + Remove the selected entries from the list + Xóa khỏi danh sách + + + Remove + Xóa + + + Copy message + Copy tin nhắn + ReceiveRequestDialog + + QR Code + QR Code + + + Copy &URI + Copy &URI + Copy &Address &Copy Địa Chỉ - + + &Save Image... + $Lưu hình ảnh... + + + Request payment to %1 + Yêu cầu thanh toán cho %1 + + + Payment information + Thông tin thanh toán + + + URI + URI + + + Message + Tin nhắn + + + Error encoding URI into QR Code. + Lỗi khi encode từ URI thành QR Code + + RecentRequestsTableModel + + Message + Tin nhắn + + + (no message) + (không tin nhắn) + SendCoinsDialog + + Send Coins + Gửi Coins + + + Coin Control Features + Tính năng Control Coin + + + Inputs... + Nhập... + + + automatically selected + Tự động chọn + Insufficient funds! Không đủ tiền @@ -698,6 +854,86 @@ Change: Thay đổi: + + Transaction Fee: + Phí giao dịch + + + Choose... + Chọn... + + + collapse fee-settings + Thu gọn fee-settings + + + per kilobyte + trên KB + + + Hide + Ẩn + + + total at least + Tổng cộng ít nhất + + + (read the tooltip) + (Đọc hướng dẫn) + + + Confirmation time: + Thời gian xác nhận + + + normal + Bình thường + + + fast + Nhanh + + + Send to multiple recipients at once + Gửi đến nhiều người nhận trong một lần + + + Add &Recipient + Thêm &Người nhận + + + Clear all fields of the form. + Xóa tất cả các trường trong biểu mẫu + + + Clear &All + Xóa &Tất cả + + + Balance: + Tài khoản + + + Confirm the send action + Xác nhận sự gửi + + + %1 to %2 + %1 đến %2 + + + Total Amount %1 + Tổng cộng %1 + + + or + hoặc + + + Confirm send coins + Xác nhận gửi coins + SendCoinsEntry @@ -705,15 +941,27 @@ A&mount: Lượng: + + &Label: + &Nhãn + SendConfirmationDialog - + + Yes + Đồng ý + + ShutdownWindow SignVerifyMessageDialog + + Clear &All + Xóa &Tất cả + SplashScreen @@ -723,6 +971,10 @@ TransactionDesc + + Message + Tin nhắn + TransactionDescDialog @@ -741,7 +993,11 @@ WalletModel - + + Send Coins + Gửi Coins + + WalletView diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts index b8d3cadc2..98142b7b0 100644 --- a/src/qt/locale/bitcoin_zh_CN.ts +++ b/src/qt/locale/bitcoin_zh_CN.ts @@ -41,10 +41,78 @@ &Delete 删除(&D) - + + Choose the address to send coins to + 选择要付钱过去的地址 + + + Choose the address to receive coins with + 选择要收钱进来的地址 + + + C&hoose + 选择 + + + Sending addresses + 付款地址 + + + Receiving addresses + 收款地址 + + + These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins. + 这些是你要付款过去的比特币地址。在付钱之前,务必要检查金额和收款地址是否正确。 + + + These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction. + 这些是你用来收款的比特币地址。建议在每次交易时,都使用一个新的收款地址。 + + + &Copy Address + 复制地址 + + + Copy &Label + 复制标签 + + + &Edit + 编辑 + + + Export Address List + 导出地址列表 + + + Comma separated file (*.csv) + 逗号分隔文件 (*.csv) + + + Exporting Failed + 导出失败 + + + There was an error trying to save the address list to %1. Please try again. + 存储地址列表到 %1 时发生错误。请再试一次。 + + AddressTableModel - + + Label + 标签 + + + Address + 地址 + + + (no label) + (无标签) + + AskPassphraseDialog @@ -63,7 +131,95 @@ Repeat new passphrase 重复新密码 - + + Enter the new passphrase to the wallet.<br/>Please use a passphrase of <b>ten or more random characters</b>, or <b>eight or more words</b>. + 输入钱包的新密码。<br/>密码请用<b>10 个以上的随机字符</b>,或是<b>8 个以上的字词</b>。 + + + Encrypt wallet + 加密钱包 + + + This operation needs your wallet passphrase to unlock the wallet. + 这个操作需要你的钱包密码来解锁钱包。 + + + Unlock wallet + 解锁钱包 + + + This operation needs your wallet passphrase to decrypt the wallet. + 这个操作需要你的钱包密码来把钱包解密。 + + + Decrypt wallet + 解密钱包 + + + Change passphrase + 修改密码 + + + Enter the old passphrase and new passphrase to the wallet. + 请输入钱包的旧密码和新密码。 + + + Confirm wallet encryption + 确认钱包加密 + + + Warning: If you encrypt your wallet and lose your passphrase, you will <b>LOSE ALL OF YOUR BITCOINS</b>! + 警告: 如果把钱包加密后又忘记密码,你就会从此<b>失去其中所有的比特币了</b>! + + + Are you sure you wish to encrypt your wallet? + 你确定要把钱包加密吗? + + + Wallet encrypted + 钱包已加密 + + + %1 will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer. + %1 现在要关闭,以完成加密过程。请注意,加密钱包不能完全防止入侵你的电脑的恶意程序偷取钱币。 + + + 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. + 重要: 请改用新产生的有加密的钱包文件,来取代旧钱包文件的备份。为了安全性,当你开始使用新的有加密的钱包后,旧钱包文件的备份就不能再使用了。 + + + Wallet encryption failed + 钱包加密失败 + + + Wallet encryption failed due to an internal error. Your wallet was not encrypted. + 因为内部错误导致钱包加密失败。你的钱包还是没加密。 + + + The supplied passphrases do not match. + 提供的密码不yi'zhi。 + + + Wallet unlock failed + 钱包解锁失败 + + + The passphrase entered for the wallet decryption was incorrect. + 输入用来解密钱包的密码不正确。 + + + Wallet decryption failed + 钱包解密失败 + + + Wallet passphrase was successfully changed. + 钱包密码修改成功。 + + + Warning: The Caps Lock key is on! + 警告: 大写字母锁定已开启! + + BanTableModel @@ -115,7 +271,7 @@ &About %1 - &关于 %1 + 关于 %1 Show information about %1 @@ -243,7 +399,7 @@ Request payments (generates QR codes and bitcoin: URIs) - 请求支付(生成二维码和 bitcoin: URI) + 请求支付 (生成二维码和 bitcoin: URI) Show the list of used sending addresses and labels @@ -255,7 +411,7 @@ Open a bitcoin: URI or payment request - 打开一个比特币:URI 或支付请求 + 打开一个 bitcoin: URI 或支付请求 &Command-line options @@ -388,7 +544,7 @@ CoinControlDialog Coin Selection - 币源选择(Coin Selection) + 选择钱币 Quantity: @@ -462,7 +618,151 @@ Priority 优先级 - + + Copy address + 复制地址 + + + Copy label + 复制标签 + + + Copy amount + 复制金额 + + + Copy transaction ID + 复制交易识别码 + + + Lock unspent + 锁定未花费 + + + Unlock unspent + 解锁未花费 + + + Copy quantity + 复制数目 + + + Copy fee + 复制手续费 + + + Copy after fee + 复制计费后金额 + + + Copy bytes + 复制字节数 + + + Copy priority + 复制优先度 + + + Copy dust + 复制零散金额 + + + Copy change + 复制找零金额 + + + highest + 最高 + + + higher + 很高 + + + high + + + + medium-high + 中高 + + + medium + 中等 + + + low-medium + 中低 + + + low + + + + lower + 很低 + + + lowest + 最低 + + + (%1 locked) + (锁定 %1 枚) + + + none + + + + yes + + + + no + + + + This label turns red if the transaction size is greater than 1000 bytes. + 当交易大小大于 1000 字节时,文字会变红色。 + + + This means a fee of at least %1 per kB is required. + 表示每一千字节(kB)需要至少 %1 的手续费。 + + + Can vary +/- 1 byte per input. + 每组输入可能会误差多或少 1 个字节。 + + + Transactions with higher priority are more likely to get included into a block. + 优先度较高的交易比较有可能被接受放进区块中。 + + + This label turns red if the priority is smaller than "medium". + 当优先度低于“中等”时,文字会变红色。 + + + This label turns red if any recipient receives an amount smaller than the current dust threshold. + 当任何一个收款金额小于目前的零散金额上限时,文字会变红色。 + + + Can vary +/- %1 satoshi(s) per input. + 每组输入可能有 +/- %1 个 satoshi 的误差。 + + + (no label) + (无标签) + + + change from %1 (%2) + 找零前是 %1 (%2) + + + (change) + (找零) + + EditAddressDialog @@ -485,7 +785,39 @@ &Address 地址(&A) - + + New receiving address + 新建收款地址 + + + New sending address + 新建付款地址 + + + Edit receiving address + 编辑收款地址 + + + Edit sending address + 编辑付款地址 + + + The entered address "%1" is not a valid Bitcoin address. + 输入的地址 %1 并不是有效的比特币地址。 + + + The entered address "%1" is already in the address book. + 输入的地址 %1 已经存在地址簿。 + + + Could not unlock wallet. + 无法将钱包解锁。 + + + New key generation failed. + 产生新的密钥失败了。 + + FreespaceChecker @@ -579,6 +911,10 @@ As this is the first time the program is launched, you can choose where %1 will store its data. 由于这是第一次启动此程序,您可以选择%1的数据所存储的位置 + + %1 will download and store a copy of the Bitcoin block chain. At least %2GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + %1 会下载并存储一份比特币区块链的副本。至少有 %2GB 的数据会存储到这个目录中,并且还会持续增长。另外钱包资料也会储存在这个目录。 + Use the default data directory 使用默认的数据目录 @@ -622,7 +958,11 @@ Select payment request file 选择付款请求文件 - + + Select payment request file to open + 选择要打开的付款请求文件 + + OptionsDialog @@ -633,6 +973,14 @@ &Main 主要(&M) + + Automatically start %1 after logging in to the system. + 在登入系统后自动启动 %1 + + + &Start %1 on system login + 系统登入时启动 %1 + Size of &database cache 数据库缓存大小(&D) @@ -759,7 +1107,7 @@ Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services. - 在Tor匿名网络下通过不同的SOCKS5代理连接比特币网络 + 在 Tor 匿名网络下通过不同的 SOCKS5 代理连接比特币网络 Use separate SOCKS5 proxy to reach peers via Tor hidden services: @@ -769,6 +1117,14 @@ &Window 窗口(&W) + + &Hide the icon from the system tray. + 不在通知区显示图标 + + + Hide tray icon + 不显示通知区图标 + Show only a tray icon after minimizing the window. 最小化窗口后仅显示托盘图标 @@ -789,6 +1145,10 @@ User Interface &language: 用户界面语言(&L): + + The user interface language can be set here. This setting will take effect after restarting %1. + 可以在这里设定用户界面的语言。这个设定在重启 %1 后才会生效。 + &Unit to show amounts in: 比特币金额单位(&U): @@ -846,7 +1206,7 @@ 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. - 现在显示的消息可能是过期的. 在连接上比特币网络节点后,您的钱包将自动与网络同步,但是这个过程还没有完成。 + 现在显示的消息可能是过期的。在连接上比特币网络节点后,您的钱包将自动与网络同步,但是这个过程还没有完成。 Watch-only: @@ -915,7 +1275,56 @@ PaymentServer - + + Payment request error + 要求付款时发生错误 + + + Cannot start bitcoin: click-to-pay handler + 无法启动 bitcoin 协议的“ +一键支付”处理器 + + + URI handling + URI 处理 + + + Payment request fetch URL is invalid: %1 + 取得付款请求的 URL 无效: %1 + + + Invalid payment address %1 + 无效的付款地址 %1 + + + URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters. + 无法解析 URI 地址!可能是因为比特币地址无效,或是 URI 参数格式错误。 + + + Payment request file handling + 处理付款请求文件 + + + Payment request file cannot be read! This can be caused by an invalid payment request file. + 无法读取付款请求文件!可能是文件无效造成的。 + + + Payment request rejected + 付款请求已被拒绝 + + + Payment request network doesn't match client network. + 付款请求的网络类型跟客户端不符。 + + + Payment request expired. + 付款请求已过期。 + + + Payment acknowledged + 付款已确认 + + PeerTableModel @@ -972,7 +1381,23 @@ QRImageWidget - + + &Save Image... + 保存图片(&S)... + + + &Copy Image + 复制图片 + + + Save QR Code + 保存二维码 + + + PNG Image (*.png) + PNG 图像(*.png) + + RPCConsole @@ -999,6 +1424,10 @@ Using BerkeleyDB version 使用的 BerkeleyDB 版本 + + Datadir + 数据目录 + Startup time 启动时间 @@ -1083,6 +1512,14 @@ User Agent 用户代理 + + Decrease font size + 缩小文字 + + + Increase font size + 放大文字 + Services 服务 @@ -1107,6 +1544,10 @@ Ping Time Ping 时间 + + The duration of a currently outstanding ping. + 目前这一次 ping 已经过去的时间。 + Ping Wait Ping等待 @@ -1141,7 +1582,7 @@ In: - 输入: + 输入: Out: @@ -1183,6 +1624,10 @@ &Unban Node (&U)允许节点连接 + + Welcome to the %1 RPC console. + 欢迎使用 %1 的 RPC 控制台。 + Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. 使用上下方向键浏览历史, <b>Ctrl-L</b>清除屏幕。 @@ -1310,7 +1755,19 @@ Remove 移除 - + + Copy label + 复制标签 + + + Copy message + 复制消息 + + + Copy amount + 复制金额 + + ReceiveRequestDialog @@ -1329,9 +1786,53 @@ &Save Image... 保存图片(&S)... - + + URI + URI + + + Address + 地址 + + + Amount + 金额 + + + Label + 标签 + + + Message + 消息 + + + Error encoding URI into QR Code. + 把 URI 编码成二维码时发生错误。 + + RecentRequestsTableModel + + Date + 日期 + + + Label + 标签 + + + Message + 消息 + + + (no label) + (无标签) + + + (no message) + (无消息) + SendCoinsDialog @@ -1483,7 +1984,59 @@ S&end 发送(&E) - + + Copy quantity + 复制数目 + + + Copy amount + 复制金额 + + + Copy fee + 复制手续费 + + + Copy after fee + 复制计费后金额 + + + Copy bytes + 复制字节数 + + + Copy priority + 复制优先度 + + + Copy dust + 复制零散金额 + + + Copy change + 复制找零金额 + + + Total Amount %1 + 总金额 %1 + + + or + + + + Payment request expired. + 付款请求已过期。 + + + Warning: Invalid Bitcoin address + 警告: 比特币地址无效 + + + (no label) + (无标签) + + SendCoinsEntry @@ -1565,9 +2118,17 @@ SendConfirmationDialog - + + Yes + + + ShutdownWindow + + %1 is shutting down... + 正在关闭 %1 ... + Do not shut down the computer until this window disappears. 在此窗口消失前不要关闭计算机。 @@ -1676,7 +2237,43 @@ TransactionDesc - + + Date + 日期 + + + Message + 消息 + + + Merchant + 商家 + + + Debug information + 调试信息 + + + Transaction + 交易 + + + Inputs + 输入 + + + Amount + 金额 + + + true + + + + false + + + TransactionDescDialog @@ -1686,10 +2283,130 @@ TransactionTableModel + + Date + 日期 + + + Type + 种类 + + + Label + 标签 + + + Received with + 收款 + + + Sent to + 付款 + + + Mined + 挖矿所得 + + + (no label) + (无标签) + TransactionView - + + All + 全部 + + + Today + 今天 + + + This week + 这星期 + + + This month + 这个月 + + + Last month + 上个月 + + + This year + 今年 + + + Range... + 指定范围... + + + Received with + 收款 + + + Sent to + 付款 + + + To yourself + 给自己 + + + Mined + 挖矿所得 + + + Other + 其它 + + + Copy address + 复制地址 + + + Copy label + 复制标签 + + + Copy amount + 复制金额 + + + Copy transaction ID + 复制交易识别码 + + + Comma separated file (*.csv) + 逗号分隔文件 (*.csv) + + + Date + 日期 + + + Type + 种类 + + + Label + 标签 + + + Address + 地址 + + + Exporting Failed + 导出失败 + + + to + + + UnitDisplayStatusBarControl @@ -1705,6 +2422,18 @@ WalletView + + Backup Wallet + 备份钱包 + + + Backup Failed + 备份失败 + + + Backup Successful + 备份成功 + bitcoin-core @@ -1779,7 +2508,11 @@ Bitcoin Core - 比特币核心 + Bitcoin Core + + + The %s developers + %s 开发人员 -fallbackfee is set very high! This is the transaction fee you may pay when fee estimates are not available. @@ -1861,6 +2594,10 @@ Connection options: 连接选项: + + Copyright (C) %i-%i + 版权所有 (C) %i-%i + Corrupted block database detected 检测发现数据块数据库损坏。请使用 -reindex参数重启客户端。 @@ -1905,6 +2642,10 @@ Error initializing wallet database environment %s! Error initializing wallet database environment %s! + + Error loading %s + 载入 %s 时发生错误 + Error loading block database 导入数据块数据库出错 @@ -1977,6 +2718,14 @@ Specify wallet file (within data directory) 指定钱包文件(数据目录内) + + Starting network threads... + 正在启动网络线程... + + + The source code is available from %s. + 源代码可以在 %s 获得。 + Unsupported argument -benchmark ignored, use -debug=bench. 忽略不支持的选项 -benchmark,使用 -debug=bench @@ -1999,11 +2748,11 @@ Verifying blocks... - 正在验证数据库的完整性... + 正在验证区块... Verifying wallet... - 正在检测钱包的完整性... + 正在验证钱包... Wallet %s resides outside data directory %s @@ -2105,6 +2854,10 @@ Error reading from database, shutting down. 读取数据库出错,关闭中。 + + Imports blocks from external blk000??.dat file on startup + 启动时从其他来源的 blk000??.dat 文件导入区块 + Information 信息 @@ -2133,6 +2886,10 @@ RPC server options: RPC 服务器选项: + + Reducing -maxconnections from %d to %d, because of system limitations. + 因为系统的限制,将 -maxconnections 参数从 %d 降到了 %d + Rescan the block chain for missing wallet transactions on startup 重新扫描区块链以查找遗漏的钱包交易 @@ -2165,6 +2922,14 @@ This is experimental software. 这是实验性的软件。 + + Tor control port password (default: empty) + Tor 控制端口密码 (默认值: 空白) + + + Tor control port to use if onion listening enabled (default: %s) + 开启监听 onion 连接时的 Tor 控制端口号 (默认值: %s) + Transaction amount too small 交易量太小 @@ -2197,13 +2962,17 @@ Warning 警告 + + Warning: unknown new rules activated (versionbit %i) + 警告: 不明的交易规则被启用了(versionbit %i) + Whether to operate in a blocks only mode (default: %u) 是否用块方进行 (%u) Zapping all transactions from wallet... - Zapping all transactions from wallet... + 正在消除錢包中的所有交易... ZeroMQ notification options: @@ -2230,6 +2999,22 @@ (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) (1 = 保留 tx meta data , 如 account owner 和 payment request information, 2 = 不保留 tx meta data) + + -maxtxfee is set very high! Fees this large could be paid on a single transaction. + 参数 -maxtxfee 设定了很高的金额!这是你一次交易就有可能付出的最高手续费。 + + + -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction. + 参数 -paytxfee 设定了很高的金额!这是你交易付款时所要付的手续费。 + + + Do not keep transactions in the mempool longer than <n> hours (default: %u) + 不要让交易留在内存池中超过 <n> 个小时 (默认值: %u) + + + Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) + 当产生交易时,如果每千字节 (kB) 的手续费比这个值 (单位是 %s) 低,就视为没支付手续费 (默认值: %s) + How thorough the block verification of -checkblocks is (0-4, default: %u) 数据块验证 严密级别 -checkblocks (0-4, 默认: %u) @@ -2246,10 +3031,22 @@ Output debugging information (default: %u, supplying <category> is optional) 输出调试信息 (默认: %u, 提供 <category> 是可选项) + + Support filtering of blocks and transaction with bloom filters (default: %u) + 支持用 Bloom 过滤器来过滤区块和交易(默认值: %u) + + + Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments. + 网络版本字符串的总长度 (%i) 超过最大长度 (%i) 了。请减少 uacomment 参数的数目或长度。 + Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d) 尝试保持上传带宽低于(MiB/24h),0=无限制(默认:%d) + + Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported. + 找到不再支持的 -socks 参数。现在只支持 SOCKS5 协议的代理服务器,因此不可以指定 SOCKS 协议版本。 + Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay. 一个不被支持的参数 -whitelistalwaysrelay 被忽略了。请使用 -whitelistrelay 或者 -whitelistforcerelay. @@ -2258,6 +3055,10 @@ Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s) 通过Tor隐藏服务连接节点时 使用不同的SOCKS5代理 (默认: %s) + + Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. This option can be specified multiple times + JSON-RPC 连接要使用的用户名和散列密码。<userpw> 的格式是:<用户名>:<盐>$<散列值>。在 share/rpcuser 目录下有一个示范的 python 脚本。这个选项可以被多次指定。 + Warning: Unknown block versions being mined! It's possible unknown rules are in effect 警告: 未知的区块版本被挖掘!未知规则可能已生效 @@ -2356,7 +3157,7 @@ Loading block index... - 正在加载数据块索引... + 正在加载区块索引... Add a node to connect to and attempt to keep the connection open From bdd6d4c97df2052fe160f12ac507ec5946f91a07 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Fri, 2 Dec 2016 15:29:20 -0500 Subject: [PATCH 87/91] SelectCoinsMinConf: Prefer coins with fewer ancestors --- src/txmempool.cpp | 7 +++ src/txmempool.h | 3 ++ src/wallet/test/wallet_tests.cpp | 74 ++++++++++++++++---------------- src/wallet/wallet.cpp | 19 ++++++-- src/wallet/wallet.h | 4 +- 5 files changed, 65 insertions(+), 42 deletions(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 59afb2cf5..a7056554a 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1134,3 +1134,10 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe if (maxFeeRateRemoved > CFeeRate(0)) LogPrint("mempool", "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); } + +bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const { + LOCK(cs); + if (exists(txid) && std::max(mapTx.find(txid)->GetCountWithAncestors(), mapTx.find(txid)->GetCountWithDescendants()) >= chainLimit) + return false; + return true; +} diff --git a/src/txmempool.h b/src/txmempool.h index afb328b5a..8129a0537 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -595,6 +595,9 @@ class CTxMemPool /** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */ int Expire(int64_t time); + /** Returns false if the transaction is in the mempool and not within the chain limit specified. */ + bool TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const; + unsigned long size() { LOCK(cs); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index c6c505898..38637b2d5 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -78,24 +78,24 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) empty_wallet(); // with an empty wallet we can't even pay one cent - BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet)); add_coin(1*CENT, 4); // add a new 1 cent coin // with a new 1 cent coin, we still can't find a mature 1 cent - BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf( 1 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet)); // but we can find a new 1 cent - BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf( 1 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); add_coin(2*CENT); // add a mature 2 cent coin // we can't make 3 cents of mature coins - BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf( 3 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet)); // we can make 3 cents of new coins - BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf( 3 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 3 * CENT); add_coin(5*CENT); // add a mature 5 cent coin, @@ -105,33 +105,33 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38 // we can't make 38 cents only if we disallow new coins: - BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet)); // we can't even make 37 cents if we don't allow new coins even if they're from us - BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf(38 * CENT, 6, 6, 0, vCoins, setCoinsRet, nValueRet)); // but we can make 37 cents if we accept new coins from ourself - BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(37 * CENT, 1, 6, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 37 * CENT); // and we can make 38 cents if we accept all new coins - BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(38 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 38 * CENT); // try making 34 cents from 1,2,5,10,20 - we can't do it exactly - BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible) // when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5 - BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf( 7 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 7 * CENT); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // when we try making 8 cents, the smaller coins (1,2,5) are exactly enough. - BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf( 8 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK(nValueRet == 8 * CENT); BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10) - BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf( 9 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 10 * CENT); BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); @@ -145,30 +145,30 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(30*CENT); // now we have 6+7+8+20+30 = 71 cents total // check that we have 71 and not 72 - BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); - BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(71 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(!wallet.SelectCoinsMinConf(72 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); // now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20 - BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 20 * CENT); // we should get 20 in one coin BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); add_coin( 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total // now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20 - BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 3 coins BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); add_coin( 18*CENT); // now we have 5+6+7+8+18+20+30 // and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18 - BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(16 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 18 * CENT); // we should get 18 in 1 coin BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); // because in the event of a tie, the biggest coin wins // now try making 11 cents. we should get 5+6 - BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(11 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 11 * CENT); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); @@ -177,11 +177,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin( 2*COIN); add_coin( 3*COIN); add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents - BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(95 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1 * COIN); // we should get 1 BTC in 1 coin BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); - BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(195 * CENT, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); @@ -196,14 +196,14 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE // we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly - BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // but if we add a bigger coin, small change is avoided add_coin(1111*MIN_CHANGE); // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount // if we add more small coins: @@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(MIN_CHANGE * 7 / 10); // and try again to make 1.0 * MIN_CHANGE - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf) @@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) for (int i = 0; i < 20; i++) add_coin(50000 * COIN); - BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins @@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(MIN_CHANGE * 6 / 10); add_coin(MIN_CHANGE * 7 / 10); add_coin(1111 * MIN_CHANGE); - BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U); @@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(MIN_CHANGE * 6 / 10); add_coin(MIN_CHANGE * 8 / 10); add_coin(1111 * MIN_CHANGE); - BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6 @@ -254,12 +254,12 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) add_coin(MIN_CHANGE * 100); // trying to make 100.01 from these three coins - BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 10001 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE * 10105 / 100); // we should get all coins BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change - BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(MIN_CHANGE * 9990 / 100, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); @@ -269,7 +269,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // Create 676 inputs (= MAX_STANDARD_TX_SIZE / 148 bytes per input) for (uint16_t j = 0; j < 676; j++) add_coin(amt); - BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, 0, vCoins, setCoinsRet, nValueRet)); if (amt - 2000 < MIN_CHANGE) { // needs more than one input: uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt); @@ -291,8 +291,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // picking 50 from 100 coins doesn't depend on the shuffle, // but does depend on randomness in the stochastic approximation code - BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); - BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(50 * COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet)); BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2)); int fails = 0; @@ -300,8 +300,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) { // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // run the test RANDOM_REPEATS times and only complain if all of them fail - BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet , nValueRet)); - BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, vCoins, setCoinsRet2, nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(COIN, 1, 6, 0, vCoins, setCoinsRet2, nValueRet)); if (equal_sets(setCoinsRet, setCoinsRet2)) fails++; } @@ -321,8 +321,8 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) { // selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time // run the test RANDOM_REPEATS times and only complain if all of them fail - BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet , nValueRet)); - BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, vCoins, setCoinsRet2, nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet , nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(90*CENT, 1, 6, 0, vCoins, setCoinsRet2, nValueRet)); if (equal_sets(setCoinsRet, setCoinsRet2)) fails++; } @@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset) add_coin(1000 * COIN); add_coin(3 * COIN); - BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet)); + BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet)); BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN); BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7f6240262..1a33744ce 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1921,7 +1921,7 @@ static void ApproximateBestSubset(vector vCoins, +bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, vector vCoins, set >& setCoinsRet, CAmount& nValueRet) const { setCoinsRet.clear(); @@ -1946,6 +1946,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int if (output.nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? nConfMine : nConfTheirs)) continue; + if (!mempool.TransactionWithinChainLimit(pcoin->GetHash(), nMaxAncestors)) + continue; + int i = output.i; CAmount n = pcoin->vout[i].nValue; @@ -2071,10 +2074,17 @@ bool CWallet::SelectCoins(const vector& vAvailableCoins, const CAmount& ++it; } + size_t nMaxChainLength = std::min(GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT), GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)); + bool fRejectLongChains = GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS); + bool res = nTargetValue <= nValueFromPresetInputs || - SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) || - SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet)); + SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, 0, vCoins, setCoinsRet, nValueRet) || + SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, 0, vCoins, setCoinsRet, nValueRet) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, 2, vCoins, setCoinsRet, nValueRet)) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::min((size_t)4, nMaxChainLength/3), vCoins, setCoinsRet, nValueRet)) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength/2, vCoins, setCoinsRet, nValueRet)) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, nMaxChainLength, vCoins, setCoinsRet, nValueRet)) || + (bSpendZeroConfChange && !fRejectLongChains && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, std::numeric_limits::max(), vCoins, setCoinsRet, nValueRet)); // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end()); @@ -3263,6 +3273,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug) strUsage += HelpMessageOpt("-dblogsize=", strprintf("Flush wallet database activity from memory to disk log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE)); strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET)); strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB)); + strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u"), DEFAULT_WALLET_REJECT_LONG_CHAINS)); } return strUsage; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 056dcc5da..10f6ea8fe 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -51,6 +51,8 @@ static const CAmount MIN_CHANGE = CENT; static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true; //! Default for -sendfreetransactions static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false; +//! Default for -walletrejectlongchains +static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false; //! -txconfirmtarget default static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2; //! Largest (in bytes) free transaction we're willing to create @@ -668,7 +670,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface * completion the coin set and corresponding actual target value is * assembled */ - bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; + bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, uint64_t nMaxAncestors, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; bool IsSpent(const uint256& hash, unsigned int n) const; From f00066ac513774ba7fcad9e2054b209ffb2c23e8 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Fri, 2 Dec 2016 15:45:43 -0500 Subject: [PATCH 88/91] CreateTransaction: Don't return success with too-many-ancestor txn --- src/wallet/wallet.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1a33744ce..7bcb9aaf1 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2452,6 +2452,21 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt } } + if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { + // Lastly, ensure this tx will pass the mempool's chain limits + LockPoints lp; + CTxMemPoolEntry entry(txNew, 0, 0, 0, 0, false, 0, false, 0, lp); + CTxMemPool::setEntries setAncestors; + size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); + size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; + size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); + size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000; + std::string errString; + if (!mempool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { + strFailReason = _("Transaction has too long of a mempool chain"); + return false; + } + } return true; } From 4bf2bec18e5f3c613a0bf5c5fa78f6ec14dcc4f5 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Fri, 2 Dec 2016 12:20:29 -0500 Subject: [PATCH 89/91] Test for fix of txn chaining in wallet --- qa/rpc-tests/wallet.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 3c0dc0f4e..992fb8a2d 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -330,10 +330,12 @@ def run_test (self): # disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463 # '-salvagewallet', ] + chainlimit = 6 for m in maintenance: print("check " + m) stop_nodes(self.nodes) - self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3) + # set lower ancestor limit for later + self.nodes = start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3) while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]: # reindex will leave rpc warm up "early"; Wait for it to finish time.sleep(0.1) @@ -346,5 +348,26 @@ def run_test (self): assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) + # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== + + # Get all non-zero utxos together + chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] + singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) + self.nodes[0].generate(1) + node0_balance = self.nodes[0].getbalance() + # Split into two chains + rawtx = self.nodes[0].createrawtransaction([{"txid":singletxid, "vout":0}], {chain_addrs[0]:node0_balance/2-Decimal('0.01'), chain_addrs[1]:node0_balance/2-Decimal('0.01')}) + signedtx = self.nodes[0].signrawtransaction(rawtx) + singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"]) + txids = [singletxid, singletxid] + self.nodes[0].generate(1) + + # Make a long chain of unconfirmed payments without hitting mempool limit + txid_list = [] + for i in range(chainlimit*2): + txid_list.append(self.nodes[0].sendtoaddress(chain_addrs[0], Decimal('0.0001'))) + assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit*2) + assert_equal(len(txid_list), chainlimit*2) + if __name__ == '__main__': WalletTest().main() From e1ff0dbe19c3e7df21206d22bb12c686cd130b4c Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Mon, 19 Dec 2016 09:35:23 -0500 Subject: [PATCH 90/91] reduce number of lookups in TransactionWithinChainLimit --- src/txmempool.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a7056554a..63a26da32 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1137,7 +1137,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRe bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const { LOCK(cs); - if (exists(txid) && std::max(mapTx.find(txid)->GetCountWithAncestors(), mapTx.find(txid)->GetCountWithDescendants()) >= chainLimit) - return false; - return true; + auto it = mapTx.find(txid); + return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit && + it->GetCountWithDescendants() < chainLimit); } From 8e707e868d6020de0d352279eed4fcd0138f3695 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 20 Dec 2016 13:34:57 +0100 Subject: [PATCH 91/91] doc: Add #9382 to release notes --- doc/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index acfb45ae2..9d35d8e5f 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -118,6 +118,7 @@ git merge commit are mentioned. - #9290 `35174a0` Make RelayWalletTransaction attempt to AcceptToMemoryPool (gmaxwell) - #9295 `43bcfca` Bugfix: Fundrawtransaction: don't terminate when keypool is empty (jonasschnelli) - #9302 `f5d606e` Return txid even if ATMP fails for new transaction (sipa) +- #9262 `fe39f26` Prefer coins that have fewer ancestors, sanity check txn before ATMP (instagibbs) ### Tests and QA - #9159 `eca9b46` Wait for specific block announcement in p2p-compactblocks (ryanofsky)